当服务器套接字接受客户端套接字时到底发生了什么?

What things are exactly happening when server socket accept client sockets?

我正在研究套接字编程,服务器套接字accept()让我很困惑。我写了两个server socket的场景accept(),大家看看:

  1. 当服务器套接字执行 accept() 时,它会创建一个新的(客户端)套接字,该套接字绑定到与服务器套接字所在端口 不同 的端口边界。所以套接字通信是通过新绑定的端口完成的,服务器套接字(仅适用于accept())正在等待原始绑定端口上的另一个客户端连接。

我认为这不太正确,因为 (1) 端口与单个进程匹配,并且 (2) 套接字接受是 inside-process 问题,单个进程可以有多个套接字。所以想到了第二种情况,基于一些 Whosebug 的答案:

  1. 当服务器套接字执行 accept() 时,它会创建一个 绑定到任何特定端口的新(客户端)套接字。当客户端与服务器通信时,它使用绑定到服务器套接字(accept()s 连接)的端口哪个客户端套接字 实际通信由来自 TCP header(?) 的 (sourceIP, sourcePort, destIP, destPort) 元组在传输级别解析(这也很可疑,因为我认为套接字有点像 application-level object)

这种情况也引发了一些问题。如果套接字通信仍然使用服务器套接字的端口,即客户端向服务器套接字端口发送一些消息,它是否使用服务器套接字的积压queue?我的意思是,如何区分来自客户端的消息 connect()read() or write()?以及如何将它们解析到服务器中的每个客户端套接字,没有任何端口绑定?

如果我的情景之一是正确的,那么它是否可以回答以下问题?或许,我的两种情况都是错误的。如果您能指导我正确答案,或者至少指导我学习一些相关文本,我将不胜感激。

来自 Linux 程序员手册,通过 man 2 accept 找到。 Link

The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). It extracts the first connection request on the queue of pending connections for the listening socket, sockfd, creates a new connected socket, and returns a new file descriptor referring to that socket. The newly created socket is not in the listening state. The original socket sockfd is unaffected by this call.

那么发生的事情是您有一个正在侦听的 TCP 套接字。有人请求 connect().

然后您调用 accept()。旧的监听套接字保持监听模式,而新的套接字以连接模式创建。端口是原来的监听端口。

这不会干扰侦听套接字,因为新套接字不会侦听传入连接。

当您创建一个套接字并在该套接字上进行绑定然后进行侦听时,您所拥有的就是所谓的 listening socket。 当建立连接时,这个套接字基本上被克隆到一个新的套接字,这个套接字被称为the servicing socket它绑定的端口仍然与原始端口相同。

但是这个套接字和之前的监听套接字有一个重要的区别。即它是socket pair的一部分。 唯一标识连接的是套接字对。因此图中有 2 个套接字对,TCP 通信通道的两端有 2 个 IP 地址和 2 个端口。在服务套接字的克隆过程中,TCP 内核将分配所谓的 TCB 并在其中存储这 2 个 IP@ 和 2 个端口。 TCB 还包含属于 TCB 的套接字号。

每次一个 TCP 段进来时,都会检查 TCP header 并检查它是否是 SYN,对于 SYN,你会建立连接,这样你就已经通过了,但是内核是浏览其监听套接字列表。如果它是一个普通的 TCP 数据包,而不是 SYN,两个端口号都在 TCP header 中并且 IP@ 是 IP header 的一部分,因此内核可以使用此信息找到属于此 TCP 连接的 TCP。 (对于 SYN,也有此信息,但正如我所说,对于 SYN,您只需处理侦听套接字)

简而言之,它是如何工作的。

此信息可在 UNIX 网络编程:套接字网络 API 中找到。在那里描述了套接字的 link 而在其他参考文献 material 中通常没有详细描述,而是通常突出显示 TCP 的细节。

When server socket do accept(), it creates a new (client) socket that is bind to port that is different from the port server socket is bind. So socket communication is done via newly bind port, and server socket (for accept() only) is waiting for another client connection on originally bind port.

没有

I think this is not quite proper answer

答案错误。

because (1) port matches to a single process

这并不意味着任何相关内容。

and (2) socket accept is inside-process matters

也不是。实际上它似乎没有任何意义。

and single process can have multiple sockets.

是的,但这与您的答案错误的原因没有任何关系。您的回答错误的原因是没有使用第二个端口。

When server socket do accept(), it creates a new (client) socket that is not bind to any specific port

没有。它创建了第二个套接字,它继承了服务器套接字的所有内容:端口号、缓冲区大小、套接字选项……除了文件描述符和 LISTENING 状态之外的所有内容,也许我忘记了其他东西。然后它将套接字的远程 IP:port 设置为客户端的远程套接字,并将套接字置于 ESTABLISHED 状态。

and when client communicates with the server

客户端已经与服务器通信。这就是我们创建此套接字的原因。

it uses the port that is bind to server socket (who accept()s connections) and which client socket to actually communicate is resolved by (sourceIP, sourcePort, destIP, destPort) tuple from TCP header(?) at Transmission level

这已经发生了。

This is also suspicious because I thought socket is somewhat application-level object)

不,不是。套接字是 kernel-level object 和 application-level 文件描述符来标识它。

If the socket communications still use server socket's port, i.e. client sends some messages to server socket port, doesn't it uses server socket's backlog queue?

没有。积压 queue 用于传入的连接请求,而不是数据。传入数据进入套接字接收缓冲区。

I mean, how can messages from client be distinguished between connect() and read() or write()?

因为 connect() 请求在 TCP header 中设置了特殊位。最后一部分可以结合数据

And how can they be resolved to each client sockets in server, WITHOUT any port binding?

端口绑定在调用 accept() 时创建套接字时发生。你自己发明了这个困难。这不是真的。

If one of my scenario is correct, would answer to the questions following?

两者都不正确。

Or possibly I'm making two wrong scenarios, so it would be very thankful for you to provide right answers, or at least some relevant texts to study.

确定你已经有相关的课文要学习了?如果你不这样做,你应该阅读 RFC 793 或 W.R。 Stevens,TCP/IP Illustrated, 第一卷,相关章节。你这里有几个主要的误解。