首先,實際上我是 Java 開發人員,對于 C 開發人員來說,這段代碼可能不清楚,抱歉....
我嘗試使用本機 C 編程獲取網路介面資訊。
這是我的示例代碼:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <linux/if_link.h>
#include <linux/types.h>
#include <sys/socket.h>
#include <list>
using namespace std ;
class Network {
private:
struct ifaddrs *ifaddrs ;
char host[NI_MAXHOST];
public:
Network() {
if (getifaddrs(&ifaddrs) == -1) {
perror("getifaddrs");
exit(EXIT_FAILURE);
}
}
~Network() {
freeifaddrs(ifaddrs);
}
list<string> interfaces() {
list<string> names ;
for (struct ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL) continue ;
if (ifa->ifa_addr->sa_family == AF_PACKET) {
names.push_back(ifa->ifa_name);
}
}
return names ;
}
int mac_addr(const char *name,char *mac_addr) {
int s;
struct ifreq buffer;
s = socket(PF_INET, SOCK_DGRAM, 0);
memset(&buffer, 0x00, sizeof(buffer));
strcpy(buffer.ifr_name, name);
ioctl(s, SIOCGIFHWADDR, &buffer);
close(s);
char *data = buffer.ifr_hwaddr.sa_data;
sprintf(mac_addr,
"x:x:x:x:x:x",
(unsigned char)data[0],
(unsigned char)data[1],
(unsigned char)data[2],
(unsigned char)data[3],
(unsigned char)data[4],
(unsigned char)data[5]);
return 0 ;
}
int ipaddr(const char *name, bool ipv4,bool netmask,char *ip) {
void * tmpAddrPtr;
for (struct ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL) continue ;
int family = ifa->ifa_addr->sa_family ;
if (strcmp(ifa->ifa_name,name) == 0 && family == AF_INET && ipv4) {
tmpAddrPtr = netmask ?
&((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr :
&((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr ;
inet_ntop(AF_INET, tmpAddrPtr, ip, INET_ADDRSTRLEN);
return 0 ;
} else if (strcmp(ifa->ifa_name,name) == 0 && family == AF_INET6 && !ipv4) {
tmpAddrPtr = netmask ?
&((struct sockaddr_in *)(ifa->ifa_netmask))->sin_addr :
&((struct sockaddr_in *)(ifa->ifa_addr))->sin_addr ;
inet_ntop(AF_INET6, tmpAddrPtr, ip, INET6_ADDRSTRLEN);
return 0 ;
}
}
return 1 ;
}
int link_stats(const char *name,struct rtnl_link_stats *stats) {
for (struct ifaddrs *ifa = ifaddrs ; ifa != NULL ; ifa = ifa->ifa_next)
{
if (ifa->ifa_addr == NULL) continue ;
int family = ifa->ifa_addr->sa_family ;
if (strcmp(ifa->ifa_name,name) == 0 && family == AF_PACKET && ifa->ifa_data != NULL) {
stats = (struct rtnl_link_stats *) ifa->ifa_data;
return 0 ;
}
}
return 1 ;
}
} ;
int main() {
Network network ;
list<string> interface_list = network.interfaces() ;
list<string>::iterator it ;
const char* ethernet = "wlan0" ;
char *ip = new char[16] ;
struct rtnl_link_stats *stats ;
network.ipaddr(ethernet,true,false,ip) ;
network.link_stats(ethernet,stats) ;
cout << "Ethernet Name: " << ethernet << endl ;
cout << "Ethernet IP: " << ip << endl ;
printf("\t\ttx_packets = u; rx_packets = u\n"
"\t\ttx_bytes = u; rx_bytes = u\n",
stats->tx_packets, stats->rx_packets,
stats->tx_bytes, stats->rx_bytes);
free(ip);
return 0;
}
第一個問題:
為什么這段代碼有時會導致分段錯誤?!
> make
mkdir -p build
c -g -o build/main main.cpp
strip --strip-all build/main
--------------------------------------------------------
> ./build/main
Segmentation fault (core dumped)
> ./build/main
Segmentation fault (core dumped)
> ./build/main
Ethernet Name: wlan0
Ethernet IP: 192.168.1.123
tx_packets = 0; rx_packets = 4294967295
tx_bytes = 32615; rx_bytes = 495411392
> ./build/main
Ethernet Name: wlan0
Ethernet IP: 192.168.1.123
tx_packets = 3077881989; rx_packets = 818185032
tx_bytes = 609520456; rx_bytes = 5081928
> ./build/main
Segmentation fault (core dumped)
第二個問題:
為什么結果不穩定?!
例如 tx_bytes 有時會回傳32615or 609520456or ... 。
uj5u.com熱心網友回復:
為什么會出現段錯誤?
int ipaddr(const char *name, bool ipv4,bool netmask,char *ip) {
...
inet_ntop(AF_INET, tmpAddrPtr, ip, INET_ADDRSTRLEN);
...
int main() {
char *ip;
network.ipaddr(ethernet,true,false,ip) ;
您正在使用未初始化的指標ip。
我會這樣修復它
變身ip為string
string ip;
更改ipaddr為通過參考獲取該引數
int ipaddr(const char *name, bool ipv4,bool netmask,string& ip) {
在呼叫之前立即將字串調整為正確的大小inet_ntop,然后用于string::data獲取所需的指標inet_top。
ip.resize(INET_ADDRSTRLEN);
inet_ntop(AF_INET, tmpAddrPtr, ip.data(), INET_ADDRSTRLEN)
其他呼叫的類似更改inet_top
對于必須與 C API 互動的 C 程式,好的經驗法則是始終將資料保存在 C 物件(字串、向量等)中,并轉換為 C API 僅在呼叫 C API 時需要的指標。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/496793.html
