Linux C 常用網絡卡操作 (收集|整理)
阿新 • • 發佈:2019-02-10
實現靜態IP地址,掩碼,閘道器的設定
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <error.h>
#include <net/route.h>
int SetIfAddr(char *ifname, char *Ipaddr, char *mask,char *gateway)
{
int fd;
int rc;
struct ifreq ifr;
struct sockaddr_in *sin;
struct rtentry rt;
fd = socket(AF_INET, SOCK_DGRAM, 0);
if(fd < 0)
{
perror("socket error");
return -1;
}
memset(&ifr,0,sizeof(ifr));
strcpy(ifr.ifr_name,ifname);
sin = (struct sockaddr_in*)&ifr.ifr_addr;
sin->sin_family = AF_INET;
//ipaddr
if(inet_aton(Ipaddr,&(sin->sin_addr)) < 0)
{
perror("inet_aton error");
return -2;
}
if(ioctl(fd,SIOCSIFADDR,&ifr) < 0)
{
perror("ioctl SIOCSIFADDR error" );
return -3;
}
//netmask
if(inet_aton(mask,&(sin->sin_addr)) < 0)
{
perror("inet_pton error");
return -4;
}
if(ioctl(fd, SIOCSIFNETMASK, &ifr) < 0)
{
perror("ioctl");
return -5;
}
//gateway
memset(&rt, 0, sizeof(struct rtentry));
memset(sin, 0, sizeof(struct sockaddr_in));
sin->sin_family = AF_INET;
sin->sin_port = 0;
if(inet_aton(gateway, &sin->sin_addr)<0)
{
printf ( "inet_aton error\n" );
}
memcpy ( &rt.rt_gateway, sin, sizeof(struct sockaddr_in));
((struct sockaddr_in *)&rt.rt_dst)->sin_family=AF_INET;
((struct sockaddr_in *)&rt.rt_genmask)->sin_family=AF_INET;
rt.rt_flags = RTF_GATEWAY;
if (ioctl(fd, SIOCADDRT, &rt)<0)
{
zError( "ioctl(SIOCADDRT) error in set_default_route\n");
close(fd);
return -1;
}
close(fd);
return rc;
}
獲取網絡卡資訊
方法一: 通過ioctl的SIOCGIFCONF
例項1. 檢查特定的網絡卡是否存在
// ppp、wifi是否正常
static int check_ppp_wifi (int wifi_switch)
{
struct ifreq ifr;
struct ifconf ifc;
char buf[256];
int success = 0;
int wifi_exist = 0;
int ppp_exist = 0;
int ret = -1;
int sock = -1;
int count = 0;
if (wifi_switch == 0)
wifi_exist = 1;
sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
APP_LogPrintf(ALM_ERROR, "socket error\n");
goto out;
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
APP_LogPrintf(ALM_ERROR,"ioctl error\n");
goto out;
}
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (! (ifr.ifr_flags & IFF_LOOPBACK)) {
// don't count loopback
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
count ++ ;
unsigned char * ptr ;
ptr = (unsigned char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
if (strncmp("ppp0", ifr.ifr_name, 4) == 0) {
ppp_exist = 1;
if (wifi_exist) {
ret = 0;
goto out;
}
} else if (strncmp("uap0", ifr.ifr_name, 4) == 0) {
wifi_exist = 1;
if (wifi_exist) {
ret = 0;
goto out;
}
}
}
}
} else {
APP_LogPrintf(ALM_ERROR,"get mac info error\n");
goto out;
}
}
out:
if (-1 != sock)
close(sock);
return ret;
}
例項2 列舉系統所有的網絡卡資訊
#include <sys/ioctl.h>
#include <net/if.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
int main()
{
struct ifreq ifr;
struct ifconf ifc;
char buf[2048];
int success = 0;
int sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (sock == -1) {
printf("socket error\n");
return -1;
}
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(sock, SIOCGIFCONF, &ifc) == -1) {
printf("ioctl error\n");
return -1;
}
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
char szMac[64];
int count = 0;
for (; it != end; ++it) {
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) == 0) {
if (! (ifr.ifr_flags & IFF_LOOPBACK)) { // don't count loopback
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == 0) {
count ++ ;
unsigned char * ptr ;
ptr = (unsigned char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0];
snprintf(szMac,64,"%02X:%02X:%02X:%02X:%02X:%02X",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));
printf("%d,Interface name : %s , Mac address : %s \n",count,ifr.ifr_name,szMac);
}
}
}else{
printf("get mac info error\n");
return -1;
}
}
}
注意:使用的時候一定要記得關閉socket,不然可能會導致開啟檔案過多,程式崩潰。
方案二:通過getifaddrs()來實現
例項1 檢查特定網絡卡:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <linux/if.h>
#include <ifaddrs.h>
#include <arpa/inet.h>
int c_ifaddrs_netlink_status(const char *if_name )
{
struct ifaddrs *ifa = NULL, *ifList;
if (getifaddrs(&ifList) < 0) {
return -1;
}
for (ifa = ifList; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr->sa_family == AF_INET) {
if (strcmp(ifa->ifa_name, if_name) ==0) {
if (!(ifa->ifa_flags & IFF_UP)) {
printf("DEVICE_DOWN\r\n");
freeifaddrs(ifList);
return 1;
}
if (!(ifa->ifa_flags & IFF_RUNNING)) {
printf("DEVICE_UNPLUGGED\r\n");
freeifaddrs(ifList);
return 2;
}
printf("DEVICE_LINKED\r\n");
freeifaddrs(ifList);
return 3;
}
}
}
printf(stderr, "DEVICE_NONE\r\n");
freeifaddrs(ifList);
return 0;
}
int main(int argc, char* argv[])
{
int i=0;
if (argc != 2) {
fprintf(stderr, "usage: %s <ethname>\r\n", argv[0]);
return -1;
}
i = c_ifaddrs_netlink_status(argv[1]);
fprintf(stderr,"c_ifaddrs_netlink_status if_status = %d\n", i );
return 0;
}
例項2 列舉系統所有網絡卡資訊:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ifaddrs.h>
int main(int argc, char* argv[]) {
struct ifaddrs *ifc, *ifc1;
char ip[64] = {};
char nm[64] = {};
if(0 != getifaddrs(&ifc)) return -1;
ifc1 = ifc;
printf("iface\tIP address\tNetmask\n");
for (; NULL != ifc; ifc = (*ifc).ifa_next) {
printf("%s", (*ifc).ifa_name);
if (NULL != (*ifc).ifa_addr) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_addr))->sin_addr), ip, 64);
printf("\t%s", ip);
} else {
printf("\t\t");
}
if (NULL != (*ifc).ifa_netmask) {
inet_ntop(AF_INET, &(((struct sockaddr_in*)((*ifc).ifa_netmask))->sin_addr), nm, 64);
printf("\t%s", nm);
} else {
printf("\t\t");
}
printf("\n");
}
freeifaddrs(ifc1);
return 0;
}
其他:
linux程式設計獲取本機IP地址的三種方法:
- 通過gethostname()和gethostbyname()
- 通過列舉網絡卡,API介面可檢視man netdevice,,, 關注,getifaddrs(&ifAddrStruct);
- 開啟一個對外界伺服器的網路連線,通過getsockname()反查自己的IP