Socket,用來實現應用的通信,是應用非常廣的一個api,今天就來揭開它的神秘面紗。
客戶端
-
引入頭文件
#include <winsock2.h>
-
初始化socket的DLL
WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData
-
創建套接字
SOCKET socket(int domain, int type, int protocol);
-
domain 是協議域,包括
- AF_INET 對應 ipv4
- AF_INET6 對應 ipv6
-
type 是連接類型
- SOCK_STREAM,提供面向連接的穩定數據傳輸,即TCP協議。 - SOCK_DGRAM,提供的是數據報(datagram),使用UDP協議。 - protocol,一般設為0,內核會自動匹配。
-
存儲服務器信息
客戶端要去連接服務器,所以應該存儲服務器的IP地址和端口號。
這邊已經在 netinet/in.h 幫我們實現了一個結構體 struct sockaddr_in 來存儲服務器信息。作為函數參數時強制轉換為sockaddr。
struct sockaddr_in { short sin_family; // 必須為AF_INET,因為是IPv4; unsigned short sin_port; // 存儲port No struct in_addr sin_addr; //存儲IP地址 char sin_zero[8]; };
網絡的字節順序為大端法,我們要想正確通信,就必須統一格式。
那么什么是大小端呢?
大端是高位字節存在低地址中,小端是低位字節存在低地址中。
因此如果本地端口格式是小端要轉為大端。
htons(PORT)就是將本機的字節序轉化為網絡的字節序。
-
連接服務器
int connect(SOCKET sockfd, const struct sockaddr *serv_addr,socklen_t addrlen)
- SOCKET sockfd,本地的socket
- const struct sockaddr *serv_addr, 將SOCKADDR_IN的對象轉為 sockaddr 指針
- socklen_t address_len 就是sockaddr的大小
-
收發消息
ssize_t send(SOCKET sockfd, const void *buf, size_t len, int flags) ssize_t recv(SOCKET sockfd, void *buf, size_t len, int flags)
- SOCKET sockfd,本地的socket描述字
- const void *buf,字符串指針,數據緩沖區
- size_t len,接受的長度
- int flags,通常從設為0
-
斷開
int PASCAL FAR closesocket(SOCKET s);
關閉套接字
服務器
-
創建服務器套接字
-
存儲服務器信息
-
bind綁定
將服務器套接字與服務器信息綁定在一起
int bind(SOCKET socket, const struct sockaddr* address, socklen_t address_len);
- SOCKET socket,服務器本地的socket
- const struct sockaddr *address, 將SOCKADDR_IN的對象轉為 sockaddr 指針
- socklen_t address_len 就是sockaddr的大小
-
監聽
int listen(SOCKET sockfd, int backlog)
listen()函數可以讓套接字進入被動監聽狀態
sockfd為需要進入監聽狀態的套接字,backlog 為請求隊列的最大長度。
所謂被動監聽,是指當沒有客戶端請求時,套接字就會處於睡眠狀態,只有當接收到客戶端請求時,套接字才會被喚醒來響應請求。
-
accept
用accept來接受客戶端的請求,這時候會產生一個新的套接字,記重點,新的,之后的通信全部用這個新的套接字,原來的套接字還在監聽客戶端的請求。
int accept(SOCKET sockfd, struct sockaddr *addr, socklen_t *addrlen)
- SOCKET sockfd,服務器本地的socket
- struct sockaddr *addr,用於存儲客戶端的IP和端口號等
- socklen_t address_len,描述addr的大小
注意這邊的accept是會阻塞的,那么什么是阻塞,就是如果沒有接收到,那么我就會一直等在這邊,比如我們剛學c語言的scanf函數的時候,它就會阻塞到那里等待用戶輸入。
包括send和recv也是會阻塞的。
-
新套接字用來收發信息
-
關閉套接字
參考資料: