socket API accept()函数如何工作?

时间:2009-01-28 19:47:27

标签: networking sockets tcp

套接字API是TCP / IP和UDP / IP通信的事实标准(即我们所知的网络代码)。但是,其核心功能之一accept()有点神奇。

借用半正式的定义:

  

在服务器端使用accept()。   它接受收到的传入尝试   从中创建新的TCP连接   远程客户端,并创建一个新的   与套接字关联的套接字   这个连接的地址对。

换句话说,accept返回一个新的套接字,服务器可以通过该套接字与新连接的客户端进行通信。旧套接字(在其上调用accept)保持打开状态,在同一端口上侦听新连接。

accept如何运作?它是如何实现的?这个话题有很多混乱。许多人声称接受打开一个新端口,并通过它与客户沟通。但这显然不是真的,因为没有新的端口被打开。你实际上可以通过同一个端口与不同的客户端进行通信,但是如何?当多个线程在同一端口上调用recv时,数据如何知道去哪里?

我想这是客户端地址与套接字描述符相关联的内容,每当数据通过recv时,它就会被路由到正确的套接字,但我不确定。

对这种机制的内部运作进行彻底的解释会很棒。

4 个答案:

答案 0 :(得分:124)

您的困惑在于认为服务器IP:服务器端口标识了套接字。实际上,套接字由四个信息唯一标识:

Client IP : Client PortServer IP : Server Port

因此,虽然服务器IP和服务器端口在所有接受的连接中都是常量,但客户端信息可以让它跟踪所有事情的进展。

澄清事情的例子:

假设我们在192.168.1.1:80和两个客户10.0.0.110.0.0.2都有一台服务器。

10.0.0.1在本地端口1234上打开连接并连接到服务器。现在服务器有一个标识如下的套接字:

10.0.0.1:1234 - 192.168.1.1:80  

现在10.0.0.2在本地端口5678上打开连接并连接到服务器。现在服务器有两个插座,标识如下:

10.0.0.1:1234 - 192.168.1.1:80  
10.0.0.2:5678 - 192.168.1.1:80

答案 1 :(得分:64)

只是添加用户“17 of 26”

给出的答案

套接字实际上由5个元组组成 - (源IP,源端口,目标IP,目标端口,协议)。这里协议可以是TCP或UDP或任何传输层协议。该协议在来自IP数据报中“协议”字段的数据包中标识。

因此,服务器上的不同应用程序可能必须在完全相同的4元组上与同一客户端进行通信,但协议字段不同。例如

服务器端的Apache谈论(TCP上的server1.com:880-client1:1234) 和 魔兽世界谈论(UDP上的server1.com:880-client1:1234)

客户端和服务器都将处理此问题,因为即使所有其他4个字段相同,IP数据包中的协议字段也是不同的。

答案 2 :(得分:11)

当我学习这个时让我感到困惑的是,socketport这些术语表明它们是物理的东西,实际上它们只是内核用来抽象细节的数据结构网络。

因此,实现数据结构以便能够保持与不同客户端的连接。至于如何它们的实现,答案是a。)无关紧要,套接字API的目的正是实现无关紧要或b。)只是有一个看。除了强烈推荐的史蒂文斯书籍提供了一个实现的详细描述之外,请查看Linux或Solaris中的源代码或其中一个BSD。

答案 3 :(得分:1)

正如另一个人所说,套接字由4元组(客户端IP,客户端端口,服务器IP,服务器端口)唯一标识。

在服务器IP上运行的服务器进程维护一个数据库(这意味着我不关心它使用什么样的表/列表/树/数组/魔术数据结构)活动套接字并监听服务器端口。当它收到消息(通过服务器的TCP / IP堆栈)时,它会根据数据库检查客户端IP和端口。如果在数据库条目中找到客户端IP和客户端端口,则将消息传递给现有处理程序,否则将创建新的数据库条目并生成新的处理程序以处理该套接字。

在ARPAnet的早期,某些协议(一个FTP)将侦听指定端口的连接请求,并使用切换端口进行回复。该连接的进一步通信将通过切换端口。这样做是为了提高每个数据包的性能:当时计算机的速度要慢几个数量级。