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來寫一個通訊了