網路程式設計 C++ 基礎函式
一.網路程式設計的基本過程(windows)
1.呼叫socket函式建立套接字
2.呼叫bind函式分配IP地址和埠號
3.呼叫listen函式轉為可接收請求。
4.呼叫accept函式受理連線請求。
5.資料的傳送和接收
6.客戶端的請求連線
7.關閉套接字
1.建立套接字
socket(int af,int type,int protocol); //成功返回套接字控制代碼,失敗返回INVALID_SOCKET
af為協議族:PF_INET 為ipv4網際網路協議族,PF_INET6為IPv6網際網路協議族。目前普遍使用ipv4。
type為:面向連線的套接字(SOCK_STREAM),面向訊息的套接字(SOCK_DGRAM)。
一般情況下protocol可以傳遞0,除非遇到同一協議族中存在多個數據傳輸方式相同的協議。例如:TCP協議IPPROTO_TCP ,UDP協議為IPPROTO_UDP。
2.進行繫結
bind(SOCKET s,struct sockaddr *name,int addrlen); //成功返回0,失敗返回SOCKET_ERROR
addrlen:佔記憶體大小,一般使用sizeof(name)
name:指向含有本機IP地址及埠號的sockaddr型別的指標
struct sockaddr_in{
sa_family_t sin_family; //地址族 IPV4:AF_INET IPV6:AF_INET6
uint16_t sin_port; //16位埠號 ,它以網路位元組序儲存
struct in_addr sin_addr; //32位IP地址 它以網路位元組序儲存
char sin_zero[8]; //不使用 必須填充為0
}
其中
struct in_addr
{
In_addr_t s_addr; ///32位IPV4地址。
}
可分配的埠號為:0~65535,其中0~1023是知名埠不可以使用。
注意sin_port和sin_addr需要轉換成網路位元組序
位元組序轉換:htons(unsigned short);其中h代表主機位元組序,n代表網路位元組序,s指的是short,l指的是long,中間用to連線。可以理解為把short型的資料從主機位元組序轉化為網路位元組序。
將字串資訊轉為網路位元組序的整數型:
inet_addr(const char * string);成功返回32為大端序整數型值,失敗時返回INADDR_NONE.還可以檢測是否為合理ip地址。
inet_aton函式與inet_addr在功能上完全相同。只是inet_aton利用了in_addr結構體,且其使用頻率更高。
inet_ntoa(struct in_addr adr)相反,成功時返回轉換後的字串地址值,失敗返回-1;
※ 每次建立伺服器端套接字都要輸入IP地址會有些繁瑣,可以使用INADDR_ANY,如:addr.sin_addr.s_addr=htonl(INADDR_ANY).
※ 普遍使用memset()函式,主要作用是使sockaddr_in結構體中的sin_zero為0。
3.進行監聽
listen(SOCKET s,int backlog); // 成功返回0,失敗返回SOCKET_ERROR
s 為需要進入監聽狀態的套接字
backlog 為請求佇列的最大長度。
當套接字正在處理客戶端請求時,如果有新的請求進來,套接字是沒法處理的,只能把它放進緩衝區,待當前請求處理完畢後,再從緩衝區中讀取出來處理。如果不斷有新的請求進來,它們就按照先後順序在緩衝區中排隊,直到緩衝區滿。這個緩衝區,就稱為請求佇列(Request Queue)。
緩衝區的長度(能存放多少個客戶端請求)可以通過 listen() 函式的 backlog 引數指定,但究竟為多少並沒有什麼標準,可以根據你的需求來定,併發量小的話可以是10或者20。
如果將 backlog 的值設定為 SOMAXCONN,就由系統來決定請求佇列長度,這個值一般比較大,可能是幾百,或者更多。
當請求佇列滿時,就不再接收新的請求,對於 Linux,客戶端會收到 ECONNREFUSED 錯誤,對於 Windows,客戶端會收到 WSAECONNREFUSED 錯誤。
※listen() 只是讓套接字處於監聽狀態,並沒有接收請求。
4.接收
accept(SOCKET s,struct sockaddr *addr,int *addrlen); // 成功返回套接字控制代碼,失敗返回INVALID_SOCKET
它的引數與 listen() 和 connect() 是相同的。
s為伺服器端套接字
addr 為 sockaddr_in 結構體變數
addrlen 為引數 addr 的長度,可由 sizeof() 求得。
accept()返回一個新的套接字來和客服端通訊,addr儲存了客戶端的IP地址和埠號,而s是伺服器端的套接字。後面和客戶端通訊時,要使用這個新生成的套接字,而不是原來伺服器端的套接字。
※listen() 只是讓套接字進入監聽狀態,並沒有真正接收客戶端請求,listen() 後面的程式碼會繼續執行,直到遇到 accept()。accept() 會阻塞程式執行(後面程式碼不能被執行),直到有新的請求到來。
5.資料的接收與傳送
send(SOCKET s,const char * buf,int len,int flags); //成功時返回傳輸位元組數。失敗時返回SOCKET_ERROR。
其中s 表示資料傳輸物件連線的套接字控制代碼值。
buf 儲存待傳輸資料的緩衝地址值。
len要傳輸的位元組數。
flags傳輸資料時用到的多種選項資訊。一般設定為 0 或 NULL。
recv(SOCKET s,const char * buf,int len,int flags); //成功時返回接收的位元組數(收到EOF時為0),失敗返回SOCKET_ERROR.
其中s 表示資料接收物件連線的套接字控制代碼值
buf儲存結束資料的緩衝地址值
len表示接收的最大位元組數
flags表示接收資料時用到的多種選項資訊。
6.客戶端的請求連線
connect(SOCKET s,struct sockaddr *serv_addr,int addrlen); // 成功返回0,失敗返回SOCKET_ERROR
serv_addr 包含遠端主機的IP地址和埠號的指標
addrlen 遠端地址結構的長度
對於客戶端無需像伺服器端一樣使用bind()、listen()、accept()函式。
7.關閉套接字
closesocket(SOCKET s); //成功返回0 失敗返回SOCKET_ERROR
不管是客戶端還是伺服器端最後都不要忘記使用closesocket()函式關閉建立的套接字。