【Linux網路程式設計】Socket Api函式

杨谖之發表於2024-08-28

【Linux網路程式設計】Socket Api函式

TCP/IP 協議族

TCP/IP 協議族有 sockaddr_insockaddr_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。

伺服器:接受連線,客戶端:被接受連線。

相關文章