基於ARM嵌入式Linux網路編程執行個體解析

來源:互聯網
上載者:User

 ***************************************************************************************************************************
作者:EasyWave                                                                                 時間:2013.01.19

類別:Linux 應用執行個體源碼                                                                  聲明:轉載,請保留連結

注意:如有錯誤,歡迎指正。這些是我學習的日誌文章......

***************************************************************************************************************************      

         這段時間,因為項目的需要,瞭解了一下USBtoNet的驅動,同時採用IOCTL來設定MAC的地址,檢測網卡的串連狀態等等,因此,就從網路上瞭解了一下關於網路編程方面的知識.一般來說:Linux網路程式與核心互動的方法是通過ioctl來實現的,ioctl與網路通訊協定棧進行互動,可得到網路介面的資訊,網卡裝置的映射屬性和配置網路介面.並且還能夠查看,修改,刪除ARP快取的資訊,所以,我們先來瞭解一下ioctl函數的具體實現.
函數形式:

#include <sys/ioctl.h>

       int ioctl(int d, int request, ...);

類別

Request

說明

資料類型

SIOCATMARK

SIOCSPGRP

SIOCGPGRP

是否位於帶外標記

設定套介面的進程ID或進程組ID

擷取套介面的進程ID或進程組ID

int

int

int

FIONBIN

FIOASYNC

FIONREAD

FIOSETOWN

FIOGETOWN

設定/清除非阻塞I/O標誌

設定/清除訊號驅動非同步I/O標誌

擷取接收緩衝區中的位元組數

設定檔案的進程ID或進程組ID

擷取檔案的進程ID或進程組ID

int

int

int

int

int

SIOCGIFCONF

SIOCSIFADDR

SIOCGIFADDR

SIOCSIFFLAGS

SIOCGIFFLAGS

SIOCSIFDSTADDR

SIOCGIFDSTADDR

SIOCGIFBRDADDR

SIOCSIFBRDADDR

SIOCGIFNETMASK

SIOCSIFNETMASK

SIOCGIFMETRIC

SIOCSIFMETRIC

SIOCGIFMTU

SIOCxxx

擷取所有介面的清單

設定介面地址

擷取介面地址

設定介面標誌

擷取介面標誌

設定點到點地址

擷取點到點地址

擷取廣播位址

設定廣播位址

擷取子網路遮罩

設定子網路遮罩

擷取介面的測度

設定介面的測度

擷取介面MTU

(還有很多取決於系統的實現)

struct ifconf

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

struct ifreq

ARP

SIOCSARP

SIOCGARP

SIOCDARP

建立/修改ARP表項

擷取ARP表項

刪除ARP表項

struct arpreq

struct arpreq

struct arpreq

SIOCADDRT

SIOCDELRT

增加路徑

刪除路徑

struct rtentry

struct rtentry

   

 

 

相關資料結構:

1):網路介面請求結構ifreq

struct ifreq {  #define IFHWADDRLEN 6 //6個位元組的硬體地址,即MAC       union {          char ifrn_name[IFNAMESIZ]; //網路介面名稱       }ifr_ifrn;      union {          struct sockaddr ifru_addr; //本地IP地址           struct sockaddr ifru_dstaddr;//目標IP地址           struct sockaddr ifru_broadaddr;//廣播IP地址           struct sockaddr ifru_netmask;//本地子網路遮罩地址           struct sockaddr ifru_hwaddr;//本地MAC地址           short ifru_flags;//網路介面標記           int ifru_ivalue;//不同的請求含義不同           struct ifmap ifru_map;//網卡地址映射           int ifru_mtu;//傳輸單元最大值           char ifru_slave[IFNAMSIZ];//預留位置           char ifru_newname[IFNAMSIZE];//新名稱           void __user* ifru_data;//使用者資料           struct if_settings ifru_settings;//裝置通訊協定設定       }ifr_ifru;  }  #define ifr_name ifr_ifrn.ifrn_name;//介面名稱   #define ifr_hwaddr ifr_ifru.ifru_hwaddr;//MAC   #define ifr_addr ifr_ifru.ifru_addr;//本地IP   #define ifr_dstaddr ifr_ifru.dstaddr;//目標IP   #define ifr_broadaddr ifr_ifru.broadaddr;//廣播IP   #define ifr_netmask ifr_ifru.ifru_netmask;//子網路遮罩   #define ifr_flags ifr_ifru.ifru_flags;//標誌   #define ifr_metric ifr_ifru.ifru_ivalue;//介面側度   #define ifr_mtu ifr_ifru.ifru_mtu;//傳輸單元最大值   #define ifr_map ifr_ifru.ifru_map;//裝置地址映射   #define ifr_slave ifr_ifru.ifru_slave;//副裝置   #define ifr_data ifr_ifru.ifru_data;//介面使用   #define ifr_ifrindex ifr_ifru.ifru_ivalue;//網路介面序號   #define ifr_qlen ifr_ifru.ifru_ivalue;//傳輸單元長度   #define ifr_newname ifr_ifru.ifru_newname;//新名稱   #define ifr_seeting ifr_ifru.ifru_settings;//裝置通訊協定設定 

2):網卡裝置屬性ifmap

struct ifmap { //網卡裝置的映射屬性       unsigned long mem_start;//開始地址       unsigned long mem_end;//結束位址       unsigned short base_addr;//基地址       unsigned char irq;//中斷號       unsigned char dma;//DMA       unsigned char port;//連接埠   }  

3):網路設定介面ifconf

struct ifconf { //網路設定結構體是一種緩衝區       int ifc_len;//緩衝區ifr_buf的大小       union {          char__user *ifcu_buf; //繪沖區指標           struct ifreq__user* ifcu_req;//指向ifreq指標       }ifc_ifcu;  };  #define ifc_buf ifc_ifcu.ifcu_buf;//緩衝區地址   #define ifc_req ifc_ifcu.ifcu_req;//ifc_req地址

4):ARP快取操作arpreq

 struct arpreq{   struct sockaddr arp_pa;//協議地址    struct sockaddr arp_ha;//硬體地址    int arp_flags;//標記    struct sockaddr arp_netmask;//協議地址的子網路遮罩    char arp_dev[16];//查詢網路介面的名稱   }  

        ARP快取操作,包含IP地址和硬體地址的映射表, 操作ARP快取的命令字 SIOCDARP,SIOCGARP,SIOCSARP分別是刪除ARP快取的一條記錄,獲得ARP快取的一條記錄和修改ARP快取的一條記錄

相關例子[以下為網路摘錄:已經上機驗證過]:

#include <sys/types.h>   #include <stdio.h>   #include <stdlib.h>   #include <unistd.h>   #include <sys/ioctl.h>   #include <sys/socket.h>   #include <netdb.h>   #include <string.h>   #include <fcntl.h>   #include <net/if.h>     int main(int argc, char*argv[]) {      int s,sv6;      int err;      s = socket(AF_INET, SOCK_DGRAM, 0);      if (s < 0) {          perror("socket error");          return -1;      }        struct ifreq ifr;      ifr.ifr_ifindex = 2; //獲得第2個網路介面的名稱       err = ioctl(s, SIOCGIFNAME, &ifr);      if (err) {          perror("index error");      } else {          printf("the %dst interface is:%s\n", ifr.ifr_ifindex, ifr.ifr_name);      }        memcpy(ifr.ifr_name, "eth0", 5);      err = ioctl(s, SIOCGIFFLAGS, &ifr);      if (!err) {          printf("SIOCGIFFLAGS:%d\n", ifr.ifr_flags);      }      err = ioctl(s, SIOCGIFMTU, &ifr);      if (!err) {          printf("SIOCGIFMTU:%d\n", ifr.ifr_mtu);      }        err = ioctl(s, SIOCGIFHWADDR, &ifr);      if (!err) {          unsigned char* hw = ifr.ifr_hwaddr.sa_data;          printf("SIOCGIFHWADDR:%02x:%02x:%02x:%02x:%02x:%02x\n", hw[0], hw[1],                  hw[2], hw[3], hw[4], hw[5]);      }        err = ioctl(s, SIOCGIFMAP, &ifr);      if (!err) {          printf(                  "SIOCGIFMAP,mem_start:%d,mem_end:%d,base_addr:%d,ifr_map:%d,dma:%d,port:%d\n",                  ifr.ifr_map.mem_start, ifr.ifr_map.mem_end,                  ifr.ifr_map.base_addr, ifr.ifr_map.irq, ifr.ifr_map.dma,                  ifr.ifr_map.port);      }         err = ioctl(s, SIOCGIFINDEX, &ifr);      if (!err) {          printf("SIOCGIFINDEX:%d\n", ifr.ifr_ifindex);      }         err = ioctl(s, SIOCGIFTXQLEN, &ifr);      if (!err) {         printf("SIOCGIFTXQLEN:%d\n", ifr.ifr_qlen);      }       struct sockaddr_in *sin = (struct sockaddr_in*) &ifr.ifr_addr; //儲存的是二進位IP       char ip[16]; //字元數組,存放字串        memset(ip, 0, 16);      err = ioctl(s, SIOCGIFADDR, &ifr);      if (!err) {          inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16); //轉換的字串儲存到ip數組中,第二個參數是要轉換的二進位IP指標,第三個參數是轉換完成存放IP的緩衝區,最後一個參數是緩衝區的長度           printf("SIOCGIFADDR:%s\n", ip);      }         err = ioctl(s, SIOCGIFDSTADDR, &ifr);      if (!err) {          inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);          printf("SIOCGIFDSTADDR:%s\n", ip);      }       err = ioctl(s, SIOCGIFNETMASK, &ifr);      if (!err) {          inet_ntop(AF_INET, &sin->sin_addr.s_addr, ip, 16);          printf("SIOCGIFNETMASK:%s\n", ip);      }          memset(&ifr, 0, sizeof(ifr));      memcpy(ifr.ifr_name, "eth0", 5);      ioctl(s, SIOCGIFBRDADDR, &ifr);      struct sockaddr_in *broadcast = (struct sockaddr_in*) &ifr.ifr_broadaddr;        inet_ntop(AF_INET, &broadcast->sin_addr.s_addr, ip, 16); //inet_ntop將二進位IP轉換成點分十進位的字串       printf("BROADCAST IP:%s\n", ip);      close(s);  } 

執行個體二:[修改代碼後,已經上機驗證過] MAC地址的設定和擷取

#include <stdio.h>#include <string.h>#include <errno.h>#include <sys/socket.h>#include <sys/ioctl.h>#include <net/if.h>typedef unsigned char u8#define LOGD(...) do {printf(__VA_ARGS__); printf("\n");} while(0)int set_mac(u8* addr, int len);int get_mac(u8* addr, int len);int main(int argc, char*argv[]){    int ret = 0;    u8 addr[6] = {0x00, 0x00, 0x00, 0x61, 0x20, 0x58};    ret = set_mac(addr, 6);    if (ret < 0)    {        LOGD("set_mac() error");        return 0;    }    LOGD("set_mac() done");    ret = get_mac(addr, 6);    if (ret < 0)    {        LOGD("get_mac() error");        return 0;    }    LOGD("get_mac() done");    char buf[32] = {0};    snprintf(buf, 32, "%02x:%02x:%02x:%02x:%02x:%02x",        addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);    LOGD("%s", buf);    return 0;}int set_mac(u8* addr, int len){    int s;    int ret;    struct ifreq ifr;        if (len < 6)    {        LOGD("set_mac(), invalid length");        return -1;    }    s = socket(PF_INET, SOCK_DGRAM, 0);    if (s < 0)    {        LOGD("socket() error: %s", strerror(errno));        return -1;    }    strcpy(ifr.ifr_ifrn.ifrn_name, "eth0");    ifr.ifr_ifru.ifru_hwaddr.sa_family = 1;    memcpy(ifr.ifr_ifru.ifru_hwaddr.sa_data, addr, 6);    ret = ioctl(s, SIOCSIFHWADDR, &ifr);    if (ret != 0)    {        LOGD("ioctl(SIOCSIFHWADDR) error: %d(%s)", errno, strerror(errno));        return -1;    }    return 0;}int get_mac(u8* addr, int len){    int s;    int ret;    struct ifreq ifr;    if (len < 6)    {        LOGD("get_mac(), invalid length");        return -1;    }    s = socket(PF_INET, SOCK_DGRAM, 0);    if (s < 0)    {        LOGD("socket() error: %s", strerror(errno));        return -1;    }    strcpy(ifr.ifr_ifrn.ifrn_name, "eth0");    ret = ioctl(s, SIOCGIFHWADDR, &ifr);    if (ret != 0)    {        LOGD("ioctl(SIOCSIFHWADDR) error: %s", strerror(errno));        return -1;    }    memcpy(addr, ifr.ifr_ifru.ifru_hwaddr.sa_data, 6);    return 0;}

執行個體三:網卡串連狀態[修改後,已經上機驗證]

#include  <stdio.h>#include  <stdlib.h>#include  <string.h>#include  <fcntl.h>#include  <errno.h>#include  <sys/ioctl.h>#include  <sys/types.h>#include  <sys/socket.h>#include  <linux/if.h>typedef unsigned short u16;typedef unsigned int u32;typedef unsigned char u8;typedef unsigned long longu64#include  <linux/sockios.h>#include  <linux/ethtool.h>int get_netlink_status(const char *if_name);int main(int argc, char* argv[]){    if(argc != 2)     {        fprintf(stderr, "usage: %s <ethname>.\n", argv[0]);        return -1;    }    if(getuid() != 0)    {        fprintf(stderr, "Netlink Status Check Need Root User.\n");        return 1;    }        printf("Net link status: %s.\n", get_netlink_status(argv[1])==1?"up":"down");    return 0;}// if_name like "ra0", "eth0". Notice: call this function// return value:// -1 -- error , details can check errno// 1 -- interface link up// 0 -- interface link down.int get_netlink_status(const char *if_name){    int skfd;    struct ifreq ifr;    struct ethtool_value edata;    edata.cmd = ETHTOOL_GLINK;    edata.data = 0;    memset(&ifr, 0, sizeof(ifr));    strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1);    ifr.ifr_data = (char *) &edata;    if (( skfd = socket( AF_INET, SOCK_DGRAM, 0 )) == 0)        return -1;    if(ioctl( skfd, SIOCETHTOOL, &ifr ) == -1)    {        close(skfd);        return -1;    }    close(skfd);    return edata.data;}

      參考了網路上前人寫過的網路編程方面的代碼,通過自己動手驗證調試OK之後,就放到部落格中來了,感謝網路上那些共用知識的人。。。。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.