UNIX 網絡編程 chapter 4

基本TCP套接字編程

4.2 socket 函數

// 建立套接字文件描述符
#include <socket/socket.h>
//返回:若成功則返回非負描述符,出錯則爲-1
int socket(int family, int type, int protocol); 
//example : socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)

clipboard.png

clipboard.png

4.3 connect 函數

#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen);

TCP套接字
1. 調用connect會激發TCP的「三次握手」
2. 若TCP客戶沒有收到SYN分節的響應, 返回ETIMEDOUT錯誤。
3. 客戶發送SYN分節後,收到RST響應,代表在指定的端口上沒有進程在等待與之鏈接, 返回ECONNREFUSES錯誤。
4. 若客戶發送的SYN在中間某個路由器上引發了一個"destination unreachable"ICMP錯誤. 返回EHOSTUNREACH 或 ENETUNTREACH錯誤
5.調用connect失敗後,都必須調用close函數關閉當前的套接字,如要再次調用connect函數,必須先從新調用socket函數web

產生RST的三個條件:
目的地爲某端口的SYN到達,然而該端口上沒有正在監聽的服務器;
TCP想取消一個已有鏈接;
TCP接收到一個根本不存在的鏈接上的分節。編程

4.4 bind 函數

int bind(int sockfd, const struct sockaddr *servaddr, socklen_t addrlen); // 成功返回0,出錯返回-1

//IPv4 通配地址
struct sockaddr_in servaddr;
servaddr.sin_addr.s_addr = htonl (INADDR_ANY);
//IPv6 通配地址
struct sockaddr_in6 servaddr6;
servaddr.sin6_addr= in6addr_any;

clipboard.png

進程綁定非通配IP地址到套接字上的常見例子是爲多個組織提供web服務器的主機上(unp/v3/P83 挺有意思)
bind函數返回的常見錯誤是EADDRINUSE:地址已經被使用服務器

4.5 listen 函數

int listen (int sockfd, int backlog)
//成功:返回0,出錯則返回-1

backlog: 內核應該爲相應套接字排隊的最大鏈接個數
內核爲每一個監聽的套接字維護兩個隊列:socket

未完成鏈接隊列:
由某個客戶端發出併到達服務器,而服務器正在等待完成相應的TCP三路握手過程,這些套接字處於SYN_RCD狀態
已完成鏈接隊列:
每一個已完成三次握手過程的客戶對應其中一項。這些套接字處於ESTABLISHED狀態。函數

未完成鏈接隊列的個數+已完成鏈接隊列的個數不超過backlogspa

clipboard.png

clipboard.png

4.10 getpeername 和 getsockname

getsockname返回與某個套接字關聯的本地協議地址,getpeername返回與某個套接字關聯的外地協議地址。code

struct sockaddr_in cltaddr;

socklen_t len = sizeof (cltaddr);

if (getsockname(sockfd, (struct sockaddr*)(&cltaddr), &len) < 0){
  err_sys("getsockname err.");
}