【Linux網路程式設計】Socket Api函式
TCP/IP 協議族
TCP/IP 協議族有 sockaddr_in
和 sockaddr_in6
兩個專用的 socket 地址結構體,它們分別用於 IPv4 和 IPv6,在此只將 IPv4,如下為 struct sockaddr_in
:
struct sockaddr_in {
sa_family_t sin_family; // 地址族:AF_INET
u_int16_t sin_port; // 埠號,要用網路位元組序表示
struct in_addr sin_addr; // IPv4地址結構體,見下面
};
struct in_addr {
u_int32_t s_addr; // IPv4地址,需要用網路位元組序表示
};
所有專用 socket 地址結構體如 sockaddr_in
型別的變數在實際使用時都需要轉化為通用的 socket 地址型別 sockaddr
(強制轉換即可)。
建立 socket
socket 是一個可讀、可寫、可控制與可關閉的檔案描述符。使用 socket 系統呼叫可建立一個 socket,在 #include <sys/types.h>
與 #include <sys/socket.h>
中:
int socket(int domain, int type, int protocol);
- domain:IP 地址型別,AF_INET 表示 IPv4,如果使用 IPv6 則是 AF_INET6。
- type:資料傳輸方式,SOCK_STREAM 表示流服務,用於 TCP,SOCK_DGRAM 表示資料包,用於 UDP。
- protocol:一般為 0,依據 type 自動推倒協議型別。
socket 系統呼叫成功時返回一個 socket 檔案描述符,失敗則返回 -1,並設定 errno。
命名 socket
在建立 socket 後,雖然指定了協議族,但是並未指定該協議族使用哪個具體的 socket 地址,由此將一個 socket 與 socket 地址繫結則稱為給 socket 命名。命名 socket 的系統呼叫為 bind
:
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
bind 將 my_addr 所指的 socket 地址分配給未命名的 sockfd 檔案描述符,addrlen 引數指出該 socket 地址的長度。
bind 成功返回 0,失敗則返回 -1 並設定 errno。
監聽 socket
socket 被命名後,還不能馬上接受客戶的連線,需要使用 listen 的系統呼叫來建立一個監聽佇列以存放待處理的客戶連線:
int listen(int sockfd, int backlog);
sockfd 表示指定被監聽的 socket。backlog 引數提示核心監聽佇列的最大長度。而如果監聽佇列的長度超過 backlog,伺服器將不再接受新的客戶連線。建議 backlog 設定為 128。
listen 成功返回 0,失敗返回 -1 並設定 errno。
接受連線
使用 accept 系統呼叫從 listen 監聽佇列中接受一個連線:
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
sockfd 是執行過 listen 系統呼叫的監聽 socket。addr是一個新的 socket 地址,用來獲取被接受連線的遠端 socket 地址,該 socket 地址的長度有由 addrlen 指出。
accept成功時返回一個新的連線 socket,該 socket 唯一地標識了被接受的這個連線,伺服器可透過讀寫該 socket 來與被接受連線對應的客戶端通訊。accept 失敗時返回 -1 並設定 errno。
伺服器:接受連線,客戶端:被接受連線。