network模块小节

本文介绍了网络连接状态的检测方法及网络配置流程。包括通过ioctl函数实现的网卡物理连接状态检测、网络接口的IP、广播地址和子网掩码获取、MAC地址读取以及网卡设备名获取等关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

         网络是很多电子产品应用的基础,因此尤为重要。近期做的互联网电视项目 也是在建立在网络连接的基础之上,可惜我做的只是简单的porting层工作,对各种网络协议、应用以及底层驱动知之甚少。在这里小结一下network模块的工作流程。

        首先设备启动的时候会创建一个线程用来检测网络连接的状态,当网线拔出或者插上以及ip地址发生变化就会向显示界面发送相应的消息。目前是通过获取上一次网络连接状态和当前网络连接状态进行比较来判断该发送的消息类型,通过功能强大的ioctl函数。感觉这种实现方法不太好,可能会增加网卡的负担。接下来是获取DNS/IP/MAC/GATEWAY,如果获取不到IP说明网卡设备还没有正式进入工作状态,网络连接也还没有正式连通,因此需要在这里等待直到获取到IP或者能判断网络通,然后就向显示界面发送一条指定的消息,实现从初始化页面向主页面的跳转。因为进行网络连接的工作都是底层完成的,所以我的porting层的实际上只需要做对网络状态是否发生变化(插拔网线)进行检测,以及开机后等待直到网络连通之后发送跳转消息给界面的工作。

        这个过程中用到了几个通用的函数:

struct  ifreq
{
        #ifndef IFNAMSIZ
        #define IFNAMSIZ        16
        #endif

        char  ifr_name[IFNAMSIZ];
 
        union {
                struct  sockaddr ifru_addr;
                struct  sockaddr ifru_dstaddr;
                struct  sockaddr ifru_broadaddr;
                __ulong32_t      ifru_flags;
                int              ifru_metric;
                caddr_t          ifru_data;
                u_short          ifru_site6;
                __ulong32_t      ifru_mtu;
                int              ifru_baudrate;
} ifr_ifru;

 

 

一、检测网卡工作状态(物理连接)

#include <stdio.h> #include <string.h> #include <stdlib.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <net/if.h>

 

1.通过SIOCGIFFLAGS

static int network_get_netlink_status(const char *if_name)
{
	int skfd; 
	struct ifreq ifr = {0};

	if ((skfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		fprintf(stderr,"socket create failed/n");
		return LINK_ERR;
	}

	strcpy(ifr.ifr_name, if_name);
	if (ioctl(skfd,SIOCGIFFLAGS,&ifr) < 0)
	{
		fprintf("SIOCGIFFLAGS failed: %s/n", strerror(errno));

		close(skfd);
		return LINK_ERR;
	}
	if (ifr.ifr_ifru.ifru_flags & IFF_RUNNING)
		return LINK_UP;
	else
		return LINK_DOWN;
	
}

2.通过SIOCETHTOOL

static int network_detect_ethtool(int skfd, const char *if_name)
{
	struct ifreq ifr;
	struct ethtool_value edata;
	memset(&ifr, 0, sizeof(ifr));
	edata.cmd = ETHTOOL_GLINK;

	strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name)-1);
	ifr.ifr_data = (char *)&edata;

	if (ioctl(skfd, SIOCETHTOOL, &ifr) == -1)
	{
		printf("ETHTOOL_GLINK failed: %s/n", strerror(errno));
		return 2;
	}

	return edata.data;
} 

3.通过SIOCGMIIREG

static int network_detect_mii(int skfd,const char *ifname)
{
	struct ifreq ifr = {0};
	unsigned phy_id;
	unsigned short *data, mii_val;
	
	strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
	if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0)
	{
		fprintf(stderr, "SIOCGMIIPHY failed: %s/n",strerro(errno));
		(void) close(skfd);
		return 2;
	}

	data = (u16 *)(&ifr.ifr_data);
	phy_id = data[0];
	data[1] = 1;
	
	if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0)
	{
		fprintf(stderr, "SIOCGMIIREG failed: %s/n", strerror(errno));
		return 2;
	}
//      mii_val |= data[3];   
	mii_val = data[3];
	return(((mii_val & 0x0016) == 0x0004) ? 0 : 1);
} 

 

二、检测接口的inet addr,Bcast ,Mask

const int network_get_eth_info(const char *if_name)
{
	int sockfd;
	char	*address = NULL;
	struct ifreq ifr = {0};
	struct sockaddr_in *addr = {0};

	if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		printf("socket create failed.");
		return 2;
	}

	strncpy(ifr.ifr_name,if_name,IFNAMSIZ-1);

	if(ioctl(sockfd,SIOCGIFADDR,&ifr) < 0)
	{
		printf("SIOCGIFADDR on %s failed: %s/n", if_name, strerror(errno));
		return 2;
	}
	
	addr = (struct sockaddr_in *)&(ifr.ifr_addr);
	address = inet_ntoa(addr->sin_addr);
	printf("inet addr: %s ",address);

	if(ioctl(sockfd,SIOCGIFBRDADDR,&ifr) < 0)
	{
		printf("SIOCGIFADDR on %s failed: %s/n", if_name, strerror(errno));
		return 2;
	}
	addr = (struct sockaddr_in *)&ifr.ifr_broadaddr;
	address = inet_ntoa(addr->sin_addr);
	printf("Bcast: %s ",address);

	if(ioctl(sockfd,SIOCGIFNETMASK,&ifr) < 0)
	{
		printf("SIOCGIFADDR on %s failed: %s/n", if_name, strerror(errno));
		return 2;
	}
	addr = (struct sockaddr_in *)&ifr.ifr_addr;
	address = inet_ntoa(addr->sin_addr);
	printf("Mask: %s ",address);
	printf("/n");
	return 0;

} 

三、检测接口的MAC地址

static int network_get_mac(const char *if_name, void *arg)
{   
	int skfd;
	u_char * ptr;
	char *mac = (char *)arg;
	struct ifreq ifr = {0}; 
	
	if (NULL == arg)
	{
		fprintf(stderr, "(out)arg is null");
		return -1;
	}

	if ((skfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		fprintf(stderr, "create socket failed/n");
		return -1;
	}

	strcpy(ifr.ifr_name, if_name);
	if (ioctl(skfd,SIOCGIFHWADDR,&ifr) < 0)
	{
		fprintf(stderr, "(out)SIOCGIFHWADDR failed: %s", strerror(errno));
		return -1;
	}
	
	ptr =(u_char *)&ifr.ifr_ifru.ifru_hwaddr.sa_data[0]; 
	sprintf(mac, "%02x-%02x-%02x-%02x-%02x-%02x",*ptr,*(ptr+1),*(ptr+2),*(ptr+3),*(ptr+4),*(ptr+5));

	return 0;
}

四、获取网卡设备名

static int network_get_interface_name(char (*interface_name)[10])
{
	int skfd;
	int i, len, count;
	char *ifreq_pointer = NULL;
	struct ifreq *result = NULL;
	struct ifconf get_info = {0};
	
	len = 10 * sizeof(struct ifreq);
	ifreq_pointer = (char *)calloc(1, len);
	
	get_info.ifc_len = len;
	get_info.ifc_ifcu.ifcu_buf = ifreq_pointer;
	
	if ((skfd = socket(AF_INET,SOCK_STREAM,0)) < 0)
	{
		fprintf(stderr, "create socket failed/n");
		free(ifreq_pointer);
		ifreq_pointer = NULL;
		return -1;
	}

	if (ioctl(skfd, SIOCGIFCONF, &get_info) < 0)
	{
		fprintf(stderr, "SIOCGIFCONF failed: %s", strerror(errno));
		free(ifreq_pointer);
		ifreq_pointer = NULL;
		return -1;
	}
	
	count = get_info.ifc_len / sizeof(struct ifreq);
	
	result = (struct ifreq *)ifreq_pointer;
	for(i=0; i<count; i++)
	{
	   	strcpy(interface_name[i], result[i].ifr_name);
		fprintf(stderr, "the %d interface name: %s/n", i, interface_name[i]);
	}
	
        free(ifreq_pointer);
	ifreq_pointer = NULL;
		
	return count;
}

void main()
{
    int count = 0;
    char eth_name[5][10] = {0};
    
    count =  network_get_interface_name(eth_name);
} 

五、获取IP地址

static int network_get_ipaddr(char *interface_name, char *ipaddr)
{
	int sockfd;
	
	struct ifreq ifr;
	struct sockaddr_in *sin;

	if((NULL == interface_name) || (NULL == ipaddr))
	{
		printf("Error argument \n");
		return -1;
	}
	
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);
	if(sockfd < 0)
	{
		printf("Socket error \n");
		return -1;
	}	
	
	bzero((char *)&ifr, sizeof(ifr));
	strcpy(ifr.ifr_name, interface_name);
	
	if (ioctl(sockfd, SIOCGIFADDR, &ifr) < 0)
	{
		printf("ioctl SIOCGIFADDR failed: %s", strerror(errno));
		return -1;
	}
	
#if 1
	sin = (struct sockaddr_in *)&ifr.ifr_addr;
	strcpy(ipaddr, (char *)inet_ntoa(sin->sin_addr));
	
#else
	struct sockaddr_in * ptr;
	ptr = (struct sockaddr_in *)&(ifr.ifr_ifru.ifru_addr);
	memcpy((char*)ipaddr, (char*)&ptr->sin_addr, sizeof(unsigned long));
	*ipaddr = swap32(*ipaddr);
	printf("IP = %s \n",inet_ntoa(ptr->sin_addr));
#endif

	close(sockfd);
	
	return 0;
}


 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值