为什么 accept() 创建一个新的套接字?

Why does accept() create a new socket?

此图演示了来自Linux编程接口

的典型客户端-服务器模型

这是来自 geeksforgeeks

的服务器端示例源代码
#include <stdio.h> 
#include <netdb.h> 
#include <netinet/in.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#define MAX 80 
#define PORT 8080 
#define SA struct sockaddr 
  
// Function designed for a chat between client and server. 
void func(int sockfd) 
{ 
    // server's job
} 
  
// Driver function 
int main() 
{ 
    int sockfd, connfd, len; 
    struct sockaddr_in servaddr, cli; 
  
    // socket create and verification 
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd == -1) { 
        printf("socket creation failed...\n"); 
        exit(0); 
    } 
    else
        printf("Socket successfully created..\n"); 
    bzero(&servaddr, sizeof(servaddr)); 
  
    // assign IP, PORT 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 
    servaddr.sin_port = htons(PORT); 
  
    // Binding newly created socket to given IP and verification 
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) { 
        printf("socket bind failed...\n"); 
        exit(0); 
    } 
    else
        printf("Socket successfully binded..\n"); 
  
    // Now server is ready to listen and verification 
    if ((listen(sockfd, 5)) != 0) { 
        printf("Listen failed...\n"); 
        exit(0); 
    } 
    else
        printf("Server listening..\n"); 
    len = sizeof(cli); 
  
    // Accept the data packet from client and verification 
    connfd = accept(sockfd, (SA*)&cli, &len); 
    if (connfd < 0) { 
        printf("server acccept failed...\n"); 
        exit(0); 
    } 
    else
        printf("server acccept the client...\n"); 
  
    // Function for chatting between client and server 
    func(connfd); 
  
    // After chatting close the socket 
    close(sockfd); 
} 

在我上面提到的那本书里,作者说

The key point to understand about accept() is that it creates a new socket, and it is this new socket that is connected to the peer socket that performed the connect().

在服务器的源代码中,有 2 个套接字

为什么服务器端不使用 sockfd 与客户端“对话”,而是创建一个新的套接字 - connfd 然后在已经存在套接字的情况下与客户端“对话” ?

一个服务器可以同时连接多个客户端。单个套接字描述符不能表示多个连接。每个连接都由本地 + 对等 address/port 对的唯一组合组成,因此服务器需要一个单独的套接字描述符来表示每个连接。

一个侦听套接字可用于接受多个连接,每个连接具有不同的远程 IP/port 对。

TCP 连接由 4 个值定义:源 IP、源端口、目标 IP、目标端口。 accept 返回的套接字描述符与此类连接相关联。相比之下,侦听套接字仅与本地IP和端口相关联。

在这个特定的代码示例中,它只调用了一次 accept。但它可以循环处理来自多个端点的连接。通常,这样的进程将有一个线程在循环中调用 accept。然后,当从 accept 返回一个新套接字时,将启动一个新线程来处理该连接,同时主线程再次调用 accept