accept() 函数是如何工作的?
Posted
技术标签:
【中文标题】accept() 函数是如何工作的?【英文标题】:How does the accept() function work? 【发布时间】:2017-05-21 15:09:16 【问题描述】:我对 C 中的 accept()
函数有疑问。
当服务器接收到连接时,accept()
函数会创建一个新的套接字与客户端通信,然后让“旧套接字”监听新的连接。
那么,我知道服务器可以通过“新套接字”与客户端通信,但是客户端如何与“新套接字”通信(因为客户端不知道这个“新套接字”)?
【问题讨论】:
客户端在服务器用socket()
知道它之前创建了“新套接字”,并用connect()
将它指向服务器。注意:二进制“socket ID”代表不同物理机上不同进程的不同内存位置。
客户端也不知道 old 套接字。
【参考方案1】:
套接字是网络编程 API 的抽象。在线上和客户端仍然只有一个连接,客户端看不到服务器是否正在使用带有监听、接受等的网络 API,或者服务器是否正在使用其他 API 或原始套接字来建立连接。
【讨论】:
【参考方案2】:在服务器端,监听socket只关联一个本地IP和端口,处于LISTEN状态。
相比之下,服务器上接受的套接字(以及客户端上连接的套接字)由本地 IP 和端口以及远程 IP 和端口标识,并处于 ESTABLISHED 状态。
在客户端,服务器使用与连接的套接字分开的侦听套接字并不重要。当客户端从connect
返回时,服务端已经从accept
返回,各自返回的socket描述符可以相互通信了。
【讨论】:
那么服务器中的多个套接字是否有可能在同一个本地端口上运行?它们是通过远程地址和端口来区分的吗? @Milack 没错。一个监听套接字可以多次调用accept
来接受多个连接。所有这些接受的套接字都将具有相同的本地 IP 和端口,但远程 IP 和/或端口会有所不同。
好的,我明白了。但是,在 connect()(在套接字“sock”上)返回之后,如果客户端在同一个套接字(“sock”)上写了一些东西,客户端接受的套接字和“新套接字”之间的“链接”是如何完成的" 用 accept() 创建?我的意思是,客户端如何自动在使用 accept() 创建的套接字上写入?
@Masiwan 客户端连接的套接字与远程 IP 和端口(即它连接的那个)以及本地 IP 和端口相关联。因此,当客户端执行send
时,它会发送到关联的远程 IP:端口。在接受的套接字的服务器端也是如此。
@dbush 所以,如果我理解的话,在 connect() 调用之前,客户端的套接字没有与远程 IP/端口相关联,但是在 connect() 返回之后(然后是 accept() return),客户端的socket是关联的?【参考方案3】:
解释是 TCP(TCP/IP 传输中的端点)由一对 IPaddress/port_number 唯一标识。当客户端请求连接时,它使用其 IP 和端口号,这是唯一的一对。该操作将 SRCIP+SRCPORT 绑定到 DSTIP+DSTPORT,这 4 个数字(两个 IP 加上两个端口)唯一标识一个连接。所以服务器上的两个套接字实际上是指两个不同的连接/流。
【讨论】:
【参考方案4】:IP 协议(包括 TCP/IP)中的任何通信都发生在两个端点之间。端点始终是主机:端口。在 TCP 世界中,两个端点标识连接。套接字与连接相关联,而不是与端点相关联。
因此,您可以从 2 个 accept() 调用返回 2 个套接字,描述 2 个不同的连接。
这是一个在 unix 机器上输出 netstat -an
的示例:
tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN
tcp 0 0 170.44.26.7:22 161.231.133.178:11550 ESTABLISHED
tcp 0 0 170.44.26.7:22 161.231.133.178:33938 ESTABLISHED
tcp 0 0 170.44.26.7:22 161.231.133.178:13875 ESTABLISHED
tcp 0 0 170.44.26.7:22 161.231.133.178:34968 ESTABLISHED
tcp 0 0 170.44.26.7:22 161.231.133.178:44212 ESTABLISHED
tcp 0 0 170.44.26.7:22 161.231.133.178:34967 ESTABLISHED
这里我们有一个监听套接字,以及由该套接字上的accept()
产生的几个连接(每个连接都由自己的套接字支持)。
【讨论】:
以上是关于accept() 函数是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章