accept() 是伺服器端從「等待佇列」取出一個已完成三向交握的連線,並回傳一個全新的 socket 描述符。原本的 listening socket 繼續監聽,新 socket 專責與該客戶端通訊。這是「一個監聽,多個通訊」並發模型的基石。
#include <sys/types.h>
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:listen() 過的 listening socketaddr:輸出參數,客戶端位址資訊 (指向 sockaddr_storage 以容納 IPv4/IPv6)addrlen:輸入輸出參數,輸入緩衝區大小,輸出實際寫入大小#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MYPORT "3490"
#define BACKLOG 10
int main(void) {
struct sockaddr_storage their_addr; // 足夠大容納 IPv4/IPv6
socklen_t addr_size;
struct addrinfo hints, *res;
int sockfd, new_fd;
// 1. 解析位址
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, MYPORT, &hints, &res);
// 2. 建立、綁定、監聽
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
bind(sockfd, res->ai_addr, res->ai_addrlen);
listen(sockfd, BACKLOG);
// 3. 等待並接受連線
addr_size = sizeof(their_addr);
new_fd = accept(sockfd, (struct sockaddr*)&their_addr, &addr_size);
if (new_fd == -1) {
perror("accept");
exit(1);
}
// 4. 新 socket 專屬通訊!
// send(new_fd, ...); recv(new_fd, ...);
// 若只處理單一連線,可關閉 listening socket
// close(sockfd);
freeaddrinfo(res);
return 0;
}
| Socket | 用途 | 生命週期 |
|---|---|---|
sockfd (listening) | 監聽埠口,接受新連線 | 伺服器啟動期間持續存在 |
new_fd (connected) | 與特定客戶端雙向通訊 | 該連線存續期間 |