Linux网卡的读写编程zz
Linux系统的所有设备都是以文件的形式存在的,所以对系统的操作可以转换为对文件的操作。本程序实现对网卡这个硬件设备进行读取操作,即也是对设备的文件进行读写操作。代码看似麻烦,但却不复杂。
主要的系统函数有:socket(),ioctl(),memcpy(),strcpy()。 两个复杂的结构体:sockaddr_in,ifreq。 .../ #include<stdio.h> #include<unistd.h> #include<sys/ioctl.h> #include<stdlib.h> #include<sys/socket.h> #include<netinet/in.h> #include<arpa/inet.h> #include<sys/types.h> #include<net/if.h> #include<string.h> unsigned char g_eth_name[16]; unsigned char g_macaddr[6]; unsigned char g_ipaddr; unsigned char g_subnetmask; unsigned char g_broadcast_ipaddr; void init_net(void) { int i; int sock; struct sockaddr_in sin; struct ifreq ifr; sock=socket(AF_INET,SOCK_DGRAM,0); if(sock==-1) printf("get the socket file descriptor faild!/n"); strcpy(g_eth_name,"etho"); strcpy(ifr.ifr_name,g_eth_name); strcpy("eth name:/t%s/n",g_eth_name); if(ioctl(sock,SIOCGIFHWADDR,&ifr)<0) printf("get the network card addr faild!/n"); memcpy(g_macaddr,ifr.ifr_hwaddr.sa_data,6); printf("the network card addr is:"); for(i=0;i<5;i++) printf("%.2x:",g_macaddr[i]); printf("%.2x:",g_macaddr[i]); if(ioctl(sock,SIOCGIFADDR,&ifr)<0) printf("get the net ip addr faild!/n"); memcpy(&sin,&ifr.ifr_addr,sizeof(sin)); g_ipaddr=sin.sin_addr.s_addr; printf("local eth0:/t%s/n",inet_ntoa(sin.sin_addr)); if(ioctl(sock,SIOCGIFBRDADDR,&ifr)<0) printf("get the broadcast ip addr faild!/n"); memcpy(&sin,&ifr.ifr_addr,sizeof(sin)); g_broadcast_ipaddr=sin.sin_addr.s_addr; printf("broadcast:/t%s/n",inet_ntoa(sin.sin_addr)); if(ioctl(sock,SIOCGIFNETMASK,&ifr)<0) printf("get the netsubmask faild!/n"); memcpy(&sin,&ifr.ifr_addr,sizeof(sin)); g_subnetmask=sin.sin_addr.s_addr; printf("subnetmask:/t%s/n",inet_ntoa(sin.sin_addr)); close(sock); } int main() { init_net(); return 0; } 代码虽长,但结构很简单。先要明白这个程序的功能是什么,这个程序是用来读取网卡的信息,其中包括网卡的ip地址,网卡的名称,网卡的MAC,网卡的子网掩码,网卡的广播地址。 代码首先包涵所必须的头文件,那些头文件可以在你要用那个系统函数时用man命令来找到。开头先定 所有记录信息的变量。 g_eth_name是网卡的名称 g_macaddr 是网卡的MAC 下面三个整型分别是子网掩码地址,网络ip地址,广播地址。接着在init_net()函数里面进行所有的操作。 首先定义一个int 的sock,这个sock好比文件的文件描述符一样。即它是网卡文件的描述符。 struct sockaddr_in 在系统的/usr/include/netinet/in.h里 struct sockaddr_in { __SOCKADDR_COMMON (sin_); in_port_t sin_port; struct in_addr sin_addr; unsigned char sin_zero[sizeof (struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof (in_port_t) - sizeof (struct in_addr)]; }; 而里面的in_addr结构 in_addr 定义为//它也在/usr/include/netinet/in.h struct in_addr{ in_addr_t s_addr; }; 其中in_addr_t 在in.h里为typedef uint32_t in_addr_t;这里的uint32_t,其中u是指unsigned,int为整型,32即为长整型所以uint32=unsigend long int 即in_addr_t s_addr=unsigend long int s_addr; 所以struct in_addr的实际定义为: struct in_addr{ unsigend long int s_addr; }; 第二个结构体定义在/usr/include/net/if.h里 struct ifreq { # define IFHWADDRLEN 6 # define IFNAMSIZ IF_NAMESIZE union { char ifrn_name[IFNAMSIZ]; } ifr_ifrn; union { struct sockaddr ifru_addr; struct sockaddr ifru_dstaddr; struct sockaddr ifru_broadaddr; struct sockaddr ifru_netmask; struct sockaddr ifru_hwaddr; short int ifru_flags; int ifru_ivalue; int ifru_mtu; struct ifmap ifru_map; char ifru_slave[IFNAMSIZ]; char ifru_newname[IFNAMSIZ]; __caddr_t ifru_data; } ifr_ifru; }; 代码用socket函数得到网卡的设备描述符存入sock里。在你的机器开启进入系统后,系统就会用你设置的网卡名来填充这个结构体,所以可以直接打印这个结构体里的ifr.ifr_name 接下来是获取网卡的MAC,用ioctl函数。这函数有三个参数,第一个是网卡的设备描述符,第三个是包涵网卡信息的ifreq结构体。第二个参数是设置索引,即你要获取的网卡信息种类。分别为 SIOCGIFHWADDR //为MAC地址 SIOCGIFADDR//为IP地址 SIOCGIFBRDADDR//为广播地址 SIOCGIFNETMASK//为子网掩码 每个获取后用memcpy函数COPY到前面定义的变量当中存储起来。然后 打印。 在main函数里调用 init_net()。 |