connect() 在分叉进程中绑定 bind() 套接字如何影响父套接字?

How does connect()'ing a bind()'ed socket in a forked process affect the socket in the parent?

我正在通过 UDP(单分配)实现一个可靠的、面向连接的应用程序。要求服务器在收到客户端的初始数据包并确认后,创建一个新的工作进程。工作进程应有一个专用于该特定客户端的套接字。

现在我看到了三种实现方法。

  1. 服务器有一个套接字,姑且称之为listener_socket,它绑定到指定的端口,等待请求。然后,我可以在子进程中,connect() 这个套接字到客户端的地址。
  2. 或者,我可以完全关闭子进程中的 listener_socket,然后打开一个全新的套接字 connection_socket,将其绑定到端口并连接到客户端。
  3. 或者,在新端口上打开一个新套接字,并改为对客户端进行编码,使其在连接的剩余时间内处理这个新端口。

我不确定(关于选项 1)是将 listener_socket 连接到客户端会如何影响父服务器中的原始 listener_socket。它会阻止父级从其他客户端接收更多消息吗?如果不是,为什么?他们最终不都指的是同一个套接字吗?

至于选项 2,这很符合我的预期,“地址已在使用中”。是否有像路由器中的某些功能(即最长匹配前缀)将数据报传送到“最合适”的套接字? (好吧,TCP 已经在 accept() 中做到了这一点,因此 UDP 不太可能复制这种逻辑。)

关于选项 3,我认为它效率很低,因为它意味着我应该为每个客户端使用一个新端口。

所以有人可以建议使用哪种方法,或者是否还有其他我还不知道的方法? 谢谢。

如果fork后子进程中的套接字与父进程中的套接字相同,则它们都反映相同的内核套接字。由于绑定和连接是在内核套接字上完成的,因此对子套接字的任何更改也会影响父套接字。因此有必要创建一个新的(独立的)连接套接字。

虽然套接字需要绑定到与侦听器套接字相同的本地地址和端口,因为这是对等方期望数据包来自的地方以保持相同的 UDP 关联。

What I am uncertain about (regarding option 1) is how connecting the listener_socket to the client affect the original listener_socket in the parent server. Will it prevent the parent from receiving further messages from other clients?

是的。

If not, why? Don't they both refer ultimately to the same socket?

是的,当 parent 分叉 child 时,child 收到所有 parent 打开的文件描述符的副本,这些是指打开的文件描述 由内核管理 。因此,这些打开的文件描述在 parent 和 child 之间共享。因此,如果 child connect() 是客户端的套接字,那么 parent 和 child 都会看到

的效果

If the socket sockfd is of type SOCK_DGRAM, then [the specified address] is the address to which datagrams are sent by default, and the only address from which datagrams are received.

(Linux manual page;已强调)

As for option 2, this gives me, quite expectedly, "address already in use". Is there some functionality like in routers (i.e. longest matching prefix) that delivers datagrams to the "most fitting" socket?

什么会使一个插座比另一个更合适?无论如何,不​​。 UDP 端点仅由地址和端口标识。

Regarding option 3, I think it's quite inefficient, because it implies that I should use a new port for each client.

相对于什么来说效率低下?是的,您的选项 (3) 需要为每个客户端指定一个单独的端口,但您没有提供任何其他可行的替代方案。

但这并不是说没有其他可行的选择。如果您不想协商一个单独的端口并为每个客户端打开一个单独的套接字(例如,这是 FTP 可以操作的方式之一),那么您不能依赖 per-client UDP 套接字。在这种情况下,服务的所有传入流量都必须进入同一个套接字。但是您可以让在该套接字上接收消息的进程根据消息的源地址和端口将每条消息分派给适当的协作进程。你应该能够让这些进程都通过同一个套接字发送响应。

可以通过多种方式来设置此类系统的详细信息。它们都有一个限制,即接收所有消息的一个进程可能成为瓶颈,但实际上,我们谈论的是 I/O。主要瓶颈很可能在网络层面,而不是在接收过程中。