当服务器套接字接受客户端套接字时,究竟发生了什么?

时间:2015-03-29 16:48:55

标签: sockets tcp

我正在研究套接字编程,而服务器套接字accept()让我感到困惑。我为服务器套接字accept()编写了两个方案,请看一下:

  1. 当服务器套接字执行accept()时,它会创建一个新的(客户端)套接字,该套接字绑定到端口服务器套接字绑定的不同的端口。因此套接字通信是通过新绑定端口完成的,服务器套接字(仅限accept())正在等待最初绑定端口上的另一个客户端连接。
  2. 我认为这不是很正确的答案,因为(1)端口匹配单个进程,(2)套接字接受是进程内部事务,单个进程可以有多个套接字。所以我根据一些stackoverflow答案做了第二个场景:

    1. 当服务器套接字执行accept()时,它会创建一个绑定到任何特定端口的新(客户端)套接字,当客户端与服务器通信时,它使用绑定到服务器套接字(谁accept()的连接)和哪个客户端套接字实际通信的端口由TCP标头中的(sourceIP, sourcePort, destIP, destPort)元组解析(? )在传输级别(这也是可疑的,因为我认为socket是某种应用程序级别的对象)
    2. 这种情况也提出了一些问题。如果套接字通信仍然使用服务器套接字端口,即客户端向服务器套接字端口发送一些消息,它是否使用服务器套接字的积压队列?我的意思是,如何区分来自客户的消息connect()read() or write()?如何解决服务器中的每个客户端套接字,没有任何端口绑定?

      如果我的一个场景是正确的,会回答以下问题吗?或者我可能会制作两个错误的场景,所以非常感谢你提供正确的答案,或至少一些相关的文本来研究。

3 个答案:

答案 0 :(得分:6)

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

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

每次进入TCP段时,都会检查TCP标头是否为SYN,对于SYN,您将建立连接以便已经通过,但内核正在通过其监听列表插座。如果它是普通的TCP数据包而不是SYN,则两个端口号都在TCP头中,并且IP @是IP头的一部分,因此使用此信息,内核能够找到属于此TCP连接的TCP。 (对于SYN,此信息也存在,但正如我所说,对于SYN,您只需要处理侦听套接字)

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

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

答案 1 :(得分:6)

  

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

没有

  

我认为这不是很正确的答案

这是一个错误的答案。

  

因为(1)端口匹配单个进程

这并不代表任何相关内容。

  

和(2)套接字接受是内部处理事项

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

  

并且单个进程可以有多个套接字。

这是真的,但它与你的答案错误无关。您的答案错误的原因是因为没有使用第二个端口。

  

当服务器套接字执行accept()时,它会创建一个未绑定到任何特定端口的新(客户端)套接字

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

  

当客户端与服务器通信时

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

  

它使用绑定到服务器套接字的端口(谁接受()的连接)以及实际通信的客户端套接字由传输级别的TCP头(?)解析(sourceIP,sourcePort,destIP,destPort)元组

这已经发生了。

  

这也是可疑的,因为我认为socket是某种应用程序级别的对象)

不,不是。套接字是一个内核级对象,具有应用程序级文件描述符以标识它。

  

如果套接字通信仍然使用服务器套接字的端口,即客户端向服务器套接字端口发送一些消息,它是否使用服务器套接字的积压队列?

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

  

我的意思是,如何在connect()和read()或write()之间区分来自客户端的消息?

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

  

如何解决服务器中的每个客户端套接字,没有任何端口绑定?

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

  

如果我的一个场景是正确的,会回答以下问题吗?

它们都不正确。

  

或者我可能犯了两个错误的情景,所以非常感谢你提供正确的答案,或至少一些相关的文本来研究。

你肯定已经有相关的文字要研究了吗?如果不这样做,您应该阅读RFC 793或W.R. Stevens, TCP / IP Illustrated,第I卷,相关章节。你在这里有几个主要的误解。

答案 2 :(得分:1)

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

  

accept()系统调用与基于连接的套接字一起使用   类型(SOCK_STREAM,SOCK_SEQPACKET)。它提取第一个连接   请求侦听套接字的挂起连接队列,   sockfd,创建一个新的连接套接字,并返回一个新文件   描述该套接字的描述符。新创建的套接字不是   在聆听状态。原始套接字sockfd不受影响   这个电话。

所以会发生的是你有一个侦听TCP套接字。有人要求connect()

然后拨打accept()。旧的侦听套接字仍处于侦听模式,而新的套接字则以连接模式创建。端口是原始侦听端口。

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