網絡是很多電子產品應用的基礎,因此尤爲重要。近期做的互聯網電視項目 也是在建立在網絡連接的基礎之上,可惜我做的只是簡單的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;
一、檢測網卡工作狀態(物理連接)
1.通過SIOCGIFFLAGS
2.通過SIOCETHTOOL
3.通過SIOCGMIIREG
二、檢測接口的inet addr,Bcast ,Mask
三、檢測接口的MAC地址
四、獲取網卡設備名
五、獲取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;
}