1. 程式人生 > >Winsock(2) IPV4地址協議程式設計

Winsock(2) IPV4地址協議程式設計

本章將介紹IPV4地址協議程式設計

SOCKADDR_IN結構體

Winsock中,將IP地址和埠號指定到sockaddr_in資料結構中

typedef struct sockaddr_in {
    SHORT sin_family;	//使用IP地址族時需要指定為AF_INET
    USHORT sin_port;	//埠號
    IN_ADDR sin_addr;	//IP地址
    CHAR sin_zero[8];	//用於補齊,使結構體大小與SOCKADDR相等
} SOCKADDR_IN, *PSOCKADDR_IN;

另一種資料結構

typedef struct sockaddr {
u_short sa_family; CHAR sa_data[14]; //14位元組的協議地址 } SOCKADDR, *PSOCKADDR, FAR *LPSOCKADDR;

SOCKADDR_IN 與 SOCKADDR 的區別

SOCKADDR_IN中的sin_zero[8]用於將其大小補到與SOCKADDR相等,可以用bzero()或memset()函式將其置為零,兩者可以混用,只需要在使用時用指標進行轉換時即可. 指向sockaddr_in 的指標和指向sockaddr的指標可以相互轉換,這意味著如果一個函式所需引數型別是sockaddr時,你可以在函式呼叫的時候將一個指向 sockaddr_in的指標顯示轉換為指向sockaddr的指標;或者相反。

你只要記住,填值的時候使用sockaddr_in結構,而作為函式的引數傳入的時候轉換成sockaddr結構就行了,畢竟都是16個字元長。

IP地址結構體

typedef struct in_addr {
    union {
        struct { UCHAR s_b1,s_b2,s_b3,s_b4; } S_un_b;
        struct { USHORT s_w1,s_w2; } S_un_w;
        ULONG S_addr;
    } S_un;

    #define s_addr  S_un.S_addr    //can be used for most tcp & ip code 
#define s_host S_un.S_un_b.s_b2 #define s_net S_un.S_un_b.s_b1 #define s_imp S_un.S_un_w.s_w2 #define s_impno S_un.S_un_b.s_b4 #define s_lh S_un.S_un_b.s_b3 } IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

可以簡單地認為該結構體是一個四位元組的地址,無非是使用聯合使之能夠被更方便的使用. 大多數情況下使用 s_addr ,即聯合中的最後一種形式來賦值.

可以使用下列函式方便地將帶點的IP地址轉換為4位元組形式

unsigned long inet_addr(
    const char FAR * cp;    //引數cp為不帶結束符用點隔開的地址字串,比如 "127.0.0.1"
);

位元組順序

不同機器的位元組順序不同,有大端小端兩種. 大端位元組序:高位元組資料存放在記憶體低地址處,低位元組資料存放在記憶體高地址處. 小端位元組序:低位元組資料存放在記憶體低地址處,高位元組資料存放在記憶體高地址處.

在網路程式設計中,存在主機位元組序(host-byte order)和 網路位元組序(network-byte order). 當一個IP地址和埠號以多位元組形式存在於計算機中時,它們是主機位元組序. 當存在於網路中時,它們是網路位元組序. 網路標準規定網路中的多位元組值必須以大端位元組序存在,因此需要做相應轉換.

接下來的幾個函式用於位元組序的轉換 主機位元組序轉換為網路位元組序

u_long htonl(u_long hostlong);    //unsigned long形位元組轉換,返回值為轉換結果

int WSAHtonl(
    SOCKET s,    
    u_long hostlong,    //主機位元組序的 4 位元組資料
    u_long FAR *lpnetlong    //轉換結果儲存到lpnetlong指向的記憶體中
);

u_short htons(u_short hostshort);    //unsigned short形位元組轉換,返回值為轉換結果

int WSAHtons(
SOCKET s,    
u_short hostshort,    //主機位元組序的 2 位元組資料
u_short FAR *lpnetshort    //轉換結果儲存到lpnetlong指向的記憶體中
);

相反的,網路位元組序轉換為主機位元組序

u_long ntohl(u_long netlong);

WSANtohl(
SOCKET s,
    u_long netlong,
    u_long FAR *lphostlong
);

u_short ntohs(u_short netshort);

WSANtohs(
    SOCKET s,
    u_short netshort,
    u_short FAR *lphostshort
);

綜上,我們已經知道如何填寫一個 IPV4 地址了,程式碼如下

SOCKADDR_IN InternetAddr;	//存放IPV4地址的資料結構
INT nPortID=5150;	//埠號,這裡隨意指定為5150
InternetAddr.sin_family=AF_INET;	//使用IP地址族時需要指定為AF_INET
InternetAddr.sin_addr.s_addr=inet_addr("136.149.3.29");	//將IP地址"136.149.3.29"轉換為4位元組形式
InternetAddr.sin_port=htons(nPortID);	//將埠號從主機位元組序轉換為網路位元組序,這裡引數做了隱式轉換int->unsigned short

一般數字形式的IP不容易記憶,因此有一系列跟IP地址獲取相關的函式,這在後面將會詳細介紹 現在你已經有了IPV4地址協議的基本概念,你已經可以通過建立一個socket來寫一個通訊了