socket,ioctl獲取ip

總結一下,今天學習的關於經過socket,ioctl來得到ip,netmask等信息,其中不少內容參照了不少網上的信息,我會一一列出的我用的這個函數,就是下面這個函數,其中的有一些全局變量,很好懂,也就很少作解釋了html

 

一。下面對這個函數進行註解一下:ios

int get_nic_IP_Address() //獲取各網卡IP地址、子網掩碼數據庫

{數組

       struct ifreq ifreq;  //聲明一個struct ifreq結構體(這個結構體中有不少重要的參數,具體能夠參照第二的補充)網絡

       int sock;socket

       int i;tcp

       int tmpint;函數

       read_dev();//這個函數的功能是得到網卡名字(保存在下面提到的sys_nic_ip[][]數組中)並計算網卡總數(就是下面的sys_nic_count)post

       for (i=0;i<sys_nic_count;i++)< span="">學習

       {

              if((sock=socket(AF_INET,SOCK_STREAM,0))<0)

              {  //創建一個套接字

                     perror("socket");

                     return;

              }

              strcpy(ifreq.ifr_name,sys_nic_name[i]); //把網卡名字複製到ifreq結構體中的name變量(感受這個地方是必須的)

              if(ioctl(sock,SIOCGIFADDR,&ifreq)<0)

              {   //這裏涉及ioctl函數對於網絡文件的控制(下面會介紹)

                     sprintf(sys_nic_ip[i],"Not set");

              }

              else

              {

                     sprintf(sys_nic_ip[i],"%d.%d.%d.%d", //把ip地址提取出來,保存(理解一下socketaddr_in和socketaddr的關係)

                                   (unsigned char)ifreq.ifr_addr.sa_data[2],

                                   (unsigned char)ifreq.ifr_addr.sa_data[3],

                                   (unsigned char)ifreq.ifr_addr.sa_data[4],

                                   (unsigned char)ifreq.ifr_addr.sa_data[5]);

              }

              if(ioctl(sock,SIOCGIFNETMASK,&ifreq)<0)

              {  //個人理解是這個地方用SIOCGIFNETMASK,那麼ifreq中本來是存的ip地址,如今存成了子網掩碼了。。

                     sprintf(sys_nic_mask[i],"Not set");//把子網掩碼提取出來(但獲得的只是超網的劃分方式就是/xx)

              }

              else

              {

                     sprintf(sys_nic_mask[i],"%d",

                                   Count((unsigned char)ifreq.ifr_netmask.sa_data[2])+

                                   Count((unsigned char)ifreq.ifr_netmask.sa_data[3])+

                                   Count((unsigned char)ifreq.ifr_netmask.sa_data[4])+

                                   Count((unsigned char)ifreq.ifr_netmask.sa_data[5]));

 

              }

       }

}

列出上面最後調用函數( Count()

) 和一些全副變量

char sys_nic_ip[20][20];       //各網卡IP

char sys_nic_mask[20][20];       //各網卡子網掩碼"/xx"

int countTable[256] =

{ 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,

              3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,

              3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3,

              3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3,

              3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,

              5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3,

              3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4,

              4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3,

              3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5,

              5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5,

              5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8 };

int Count(int v)

{

       return countTable[v];

}

應該理解了吧。。。挺經典的。。。不過網上的貌似就有一個版本。。。 非常氣惱

二。 對涉及的知識點進行補充

1.struct ifreq

{

       char ifr_name[IFNAMSIZ];

       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]; /* Just fits the size */

              char ifru_newname[IFNAMSIZ];

              __caddr_t ifru_data;

       }ifr_ifru;

};

# define ifr_name ifr_ifrn.ifrn_name /* interface name */

# define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */

# define ifr_addr ifr_ifru.ifru_addr /* address */

# define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */

# define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */

# define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */

# define ifr_flags ifr_ifru.ifru_flags /* flags */

# define ifr_metric ifr_ifru.ifru_ivalue /* metric */

# define ifr_mtu ifr_ifru.ifru_mtu /* mtu */

# define ifr_map ifr_ifru.ifru_map /* device map */

# define ifr_slave ifr_ifru.ifru_slave /* slave device */

# define ifr_data ifr_ifru.ifru_data /* for use by interface */

# define ifr_ifindex ifr_ifru.ifru_ivalue /* interface index */

# define ifr_bandwidth ifr_ifru.ifru_ivalue /* link bandwidth */

# define ifr_qlen ifr_ifru.ifru_ivalue /* queue length */

# define ifr_newname ifr_ifru.ifru_newname /* New name */

# define _IOT_ifreq _IOT(_IOTS(char),IFNAMSIZ,_IOTS(char),16,0,0)

# define _IOT_ifreq_short _IOT(_IOTS(char),IFNAMSIZ,_IOTS(short),1,0,0)

# define _IOT_ifreq_int _IOT(_IOTS(char),IFNAMSIZ,_IOTS(int),1,0,0)

 

2.ioctl 函數 (在網絡中的做用)

關於這個網絡相關的請求,就是ioctl在這裏面起的做用和各個參數的做用。。。能夠參照這個網頁,講解的很詳細:

http:       //www.iteye.com/topic/309442

本例中用的2個ioctl控制函數。。上面已經解釋很清楚了

3.關於socketaddr_in和socketaddr的關係,下面貼出具體的定義:

struct sockaddr_in

{

       short int sin_family; /* 地址族 */

       unsigned short int sin_port; /* 端口號 */

       struct in_addr sin_addr; /* IP地址 */

       unsigned char sin_zero[8]; /* 填充0 以保持與struct sockaddr一樣大小 */

};

struct sockaddr

{

       unsigned short sa_family; /* 地址族, AF_xxx */

       char sa_data[14]; /* 14 字節的協議地址 */

};

比較一下,會發現長度同樣,因此這2個能夠通用的,不過要進行類型轉換, 比較一下就得出了爲何上面程序中能夠用

(unsigned char)

ifreq.ifr_addr.sa_data[2],這種形式了,仍是解釋一下吧:這個ifr_addr是一個struct sockaddr結構體。它其中的sa_date[2]是否是照着上面sockaddr_in中的sin_add(也就是ip地址呢),該明白了吧。。。。

總結:經過這個函數,能夠很好的理解怎麼獲得ip和子網掩碼的過程。。。。

 

ioctl 獲取本機網卡ip地址 | socket()

#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main()
{
int inet_sock;
struct ifreq ifr;
inet_sock = socket(AF_INET, SOCK_DGRAM, 0);
//eth0爲接口到名稱

strcpy(ifr.ifr_name, "eth1");

//SIOCGIFADDR標誌表明獲取接口地址

if (ioctl(inet_sock, SIOCGIFADDR, &ifr) == 0)
perror("ioctl");

printf("%s\n", inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr));
return 0;
}
複製代碼

--------------------------------------------------------------------------------------------------------------------------------------------------------------

ifreq結構定義在/usr/include/net/if.h,用來配置ip地址,激活接口,配置MTU等接口信息的。
其中包含了一個接口的名字和具體內容——(是個共用體,有多是IP地址,廣播地址,子網掩碼,MAC號,MTU或其餘內容)。
ifreq包含在ifconf結構中。而ifconf結構一般是用來保存全部接口的信息的。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

用ioctl得到本地ip地址時要用到兩個結構體ifconf和ifreq,它們對於大多數人
來講都是比較陌生的,這裏給你們一種比較簡單的理解方法,固然只一種幫助
理解的方法,在描述中可能會有一些地方與真實定義有所出入,僅供參考.

首先先認識一下ifconf和ifreq:

//ifconf一般是用來保存全部接口信息的
//if.h
struct ifconf 
{
    int    ifc_len;            /* size of buffer    */
    union 
    {
        char *ifcu_buf;                        /* input from user->kernel*/
        struct ifreq *ifcu_req;        /* return from kernel->user*/
    } ifc_ifcu;
};
#define    ifc_buf    ifc_ifcu.ifcu_buf        /* buffer address    */
#define    ifc_req    ifc_ifcu.ifcu_req        /* array of structures    */
 
//ifreq用來保存某個接口的信息
//if.h
struct ifreq {
    char ifr_name[IFNAMSIZ];
    union {
        struct sockaddr ifru_addr;
        struct sockaddr ifru_dstaddr;
        struct sockaddr ifru_broadaddr;
        short ifru_flags;
        int ifru_metric;
        caddr_t ifru_data;
    } ifr_ifru;
};
#define ifr_addr ifr_ifru.ifru_addr
#define ifr_dstaddr ifr_ifru.ifru_dstaddr
#define ifr_broadaddr ifr_ifru.ifru_broadaddr

 

上邊這兩個結構看起來比較複雜,咱們如今把它們簡單化一些:
好比說如今咱們向實現得到本地IP的功能。

咱們的作法是:
1. 先經過ioctl得到本地全部接口的信息,並保存在ifconf中
2. 再從ifconf中取出每個ifreq中表示ip地址的信息

具體使用時咱們能夠認爲ifconf就有兩個成員:
ifc_len 和 ifc_buf,如圖一所示:    

  

ifc_len:表示用來存放全部接口信息的緩衝區長度
ifc_buf:表示存放接口信息的緩衝區

因此咱們須要在程序開始時對ifconf的ifc_led和ifc_buf進行初始化
接下來使用ioctl獲取全部接口信息,完成後ifc_len內存放實際得到的藉口信息總長度
而且信息被存放在ifc_buf中。
以下圖示:(假設讀到兩個接口信息)

   

 

接下來咱們只須要從一個一個的接口信息獲取ip地址信息便可。

下面有一個簡單的參考:

 

 

 

#include 
#include 
#include 
#include 
#include in.h>
#include <string.h>
#include if.h>
#include 
 
int main()
{
    int i=0;
    int sockfd;
  struct ifconf ifconf;
  unsigned char buf[512];
  struct ifreq *ifreq;
  
  //初始化ifconf
  ifconf.ifc_len = 512;
  ifconf.ifc_buf = buf;
  
    if((sockfd = socket(AF_INET, SOCK_DGRAM, 0))<0)
    {
        perror("socket");
        exit(1);
    }  
  ioctl(sockfd, SIOCGIFCONF, &ifconf);    //獲取全部接口信息
  
  //接下來一個一個的獲取IP地址
  ifreq = (struct ifreq*)buf;  
  for(i=(ifconf.ifc_len/sizeof(struct ifreq)); i>0; i--)
  {
//      if(ifreq->ifr_flags == AF_INET){            //for ipv4
          printf("name = [%s]\n", ifreq->ifr_name);
      printf("local addr = [%s]\n", 
                      inet_ntoa(((struct sockaddr_in*)&(ifreq->ifr_addr))->sin_addr));
      ifreq++;
//  }
  }
    return 0;
}
 
此方法僅供參考,也適用於獲取其餘信息。

--------------------------------------------------------------------------------------------------------------------------------------------------------------

簡述:
建立一個套接口。
#include <winsock.h>
SOCKET PASCAL FAR socket( int af, int type, int protocol);
af:一個地址描述。目前僅支持AF_INET格式,也就是說ARPA Internet地址格式。
type:新套接口的類型描述。
protocol:套接口所用的協議。如調用者不想指定,可用0。

註釋


   socket()函數用於根據指定的地址族、數據類型和協議來分配一個套接口的描述字及其所用的資源。若是協議protocol未指定(等於0),則使用缺省的鏈接方式。
對於使用一給定地址族的某一特定套接口,只支持一種協議。但地址族可設爲AF_UNSPEC(未指定),這樣的話協議參數就要指定了。協議號特定於進行通信的「通信域」。支持下述類型描述:
類型 解釋
SOCK_STREAM 提供有序的、可靠的、雙向的和基於鏈接的字節流,使用帶外數據傳送機制,爲Internet地址族使用TCP。
SOCK_DGRAM 支持無鏈接的、不可靠的和使用固定大小(一般很小)緩衝區的數據報服務,爲Internet地址族使用UDP。
SOCK_STREAM類型的套接口爲全雙向的字節流。對於流類套接口,在接收或發送數據前必需處於已鏈接狀態。用 connect()調用創建與另外一套接口的鏈接,鏈接成功後,便可用 send()和recv()傳送數據。當會話結束後,調用closesocket()。帶外數據根據規定用send()和recv()來接收。
實現SOCK_STREAM類型套接口的通信協議保證數據不會丟失也不會重複。若是終端協議有緩衝區空間,且數據不能在必定時間成功發送,則認爲鏈接中斷,其後續的調用也將以WSAETIMEOUT錯誤返回。
SOCK_DGRAM類型套接口容許使用 sendto()和recvfrom()從任意端口發送或接收數據報。若是這樣一個套接口用connect()與一個指定端口鏈接,則可用send()和recv()與該端口進行數據報的發送與接收。

返回值


  若無錯誤發生,socket()返回引用新套接口的描述字。不然的話,返回INVAID_SOCKET錯誤,應用程序可經過WSAGetLastError()獲取相應錯誤代碼。
錯誤代碼:
WSANOTINITIALISED:在使用此API以前應首先成功地調用WSAStartup()。
WSAENETDOWN:WINDOWS套接口實現檢測到網絡子系統失效。
WSAEAFNOSUPPORT:不支持指定的地址族。
WSAEINPROGRESS:一個阻塞的WINDOWS套接口調用正在運行中。
WSAEMFILE:無可用文件描述字。
WSAENOBUFS:無可用緩衝區,沒法建立套接口。
WSAEPROTONOSUPPORT:不支持指定的協議。
WSAEPROTOTYPE:指定的協議不適用於本套接口。
WSAESOCKTNOSUPPORT:本地址族中不支持該類型套接口。

參見


   accept()bind(), connect(),  getsockname()getsockopt(), setsockopt(),  listen(), recv(), recvfrom(), select(), send(), sendto(), shutdown(), ioctlsocket().4.2 數據庫例程
socket()
函數原型:
SOCKET WSAAPI  socket(
int af,
int type,
int protocol
);
該函數及參數定義包含在winsock2.h頭文件中,在MSDN中查不到具體參數。
參數選項及定義:
地址族af:(經常使用AF_INET實現TCP/UDP協議)
#define AF_UNSPEC       0               /* unspecified */
#define AF_UNIX         1               /* local to host (pipes, portals) */
#define AF_INET         2               /* internetwork: UDP, TCP, etc. */
#define AF_IMPLINK      3               /* arpanet imp addresses */
#define AF_PUP          4               /* pup protocols: e.g. BSP */
#define AF_CHAOS        5               /* mit CHAOS protocols */
#define AF_NS           6               /* XEROX NS protocols */
#define AF_IPX          AF_NS           /* IPX protocols: IPX, SPX, etc. */
#define AF_ISO          7               /* ISO protocols */
#define AF_OSI          AF_ISO          /* OSI is ISO */
#define AF_ECMA         8               /* european computer manufacturers */ 
#define AF_DATAKIT      9               /* datakit protocols */
#define AF_CCITT        10              /* CCITT protocols, X.25 etc */
#define AF_SNA          11              /* IBM SNA */ 
#define AF_DECnet       12              /* DECnet */
#define AF_DLI          13              /* Direct data link interface */
#define AF_LAT          14              /* LAT */ #define AF_HYLINK       15              /* NSC Hyperchannel */ #define AF_APPLETALK    16              /* AppleTalk */ #define AF_NETBIOS      17              /* NetBios-style addresses */ #define AF_VOICEVIEW    18              /* VoiceView */ #define AF_FIREFOX      19              /* Protocols from Firefox */ #define AF_UNKNOWN1     20              /* Somebody is using this! */ #define AF_BAN          21              /* Banyan */ #define AF_ATM          22              /* Native ATM Services */ #define AF_INET6        23              /* Internetwork Version 6 */ #define AF_CLUSTER      24              /* Microsoft Wolfpack */ #define AF_12844        25              /* IEEE 1284.4 WG AF */ 套接字類型type: #define SOCK_STREAM     1               /* stream socket */ #define SOCK_DGRAM      2               /* datagram socket */ #define SOCK_RAW        3               /* raw-protocol interface */ #define SOCK_RDM        4               /* reliably-delivered message */ #define SOCK_SEQPACKET  5               /* sequenced packet stream */ 協議類型protocol: #define IPPROTO_IP              0               /* dummy for IP */ #define IPPROTO_ICMP            1               /* control message protocol */ #define IPPROTO_IGMP            2               /* internet group management protocol */ #define IPPROTO_GGP             3               /* gateway^2 (deprecated) */ #define IPPROTO_TCP             6               /* tcp */ #define IPPROTO_PUP             12              /* pup */ #define IPPROTO_UDP             17              /* user datagram protocol */ #define IPPROTO_IDP             22              /* xns idp */ #define IPPROTO_ND              77              /* UNOFFICIAL net disk proto */
相關文章
相關標籤/搜索