为 UDP 实施接受

Implementing Accept for UDP

UDP 套接字有一个 'connect' 调用,但没有对服务器应用程序的 'accept' 调用。有一些套接字 API 可以从连接的 UDP 套接字(例如 recvmmsg/sendmmsg)中提高性能,并且对于具有非常高的数据包速率的单流来说是性能最好的系统调用(任何更高的东西都需要像 DPDK 一样绕过内核)。

无论如何,我无法找到实现 UDP 服务器接受的解决方案,所以我的想法是:

  1. 服务器套接字监听直到收到来自客户端的数据包
  2. 服务器在套接字上调用连接,从而允许使用加速连接的 api 将流量发送到客户端(即连接 sendmmsg 未连接 sendmmsg
  3. 服务器侦听#1 的克隆套接字

为了解决接受问题,我不知道如何克隆#1。我的“服务器”库的用户正在传递一个套接字文件描述符,这意味着他们可以控制他们配置的选项,(SO_RECVBUFF,等等)——我看不到它。不幸的是,为了克隆它,我现在需要这种可见性。

无论如何,如果有其他方法可以解决接受问题,或者克隆套接字,我很想知道!谢谢!

没有克隆套接字的内置功能。您需要跟踪您在一个套接字上设置的任何选项,并将它们设置在一个新套接字上。

但是你有一个更大的问题。如果您在同一个端口上打开了多个 UDP 套接字并且传入了一个单播数据包,那么只有这些套接字中的一个会收到它 您无法准确预测它是哪一个。因此,为 UDP 连接使用一个“侦听”套接字和多个“接受”套接字的整个概念将行不通。

您的程序需要有一个套接字来处理所有传入的数据包,并根据发送方对它们进行多路复用,可能有一个线程用于接收,每个客户端有一个线程,但请先尝试不使用线程。

编辑:

鉴于使用已连接的 UDP 套接字,您似乎可以使用一个未连接的套接字作为侦听器,并为每个要与之交谈的远程端点使用一个已连接的套接字。由于没有克隆函数,这意味着您创建的任何用于处理不同端点的新套接字将在创建套接字和在该套接字上调用 connect 之间暂时处于未连接状态。在此期间,与已连接套接字无关的传入数据包可能会到达“侦听器”,或者它可能会在连接之前到达这个新套接字。您需要在您的应用程序中处理这种情况,最有可能的方法是让已连接的套接字丢弃未知数据包,并让客户端重试其初始“连接”直到收到响应。

你写了,

The real problem is that udp offers a 'connect' but no 'accept'

,但是不,真正的问题是UDP不是面向连接的协议。正如 the POSIX specifications for connect() 解释的那样:

If the initiating socket is not connection-mode, then connect() shall set the socket's peer address, and no connection is made. For SOCK_DGRAM sockets, the peer address identifies where all datagrams are sent on subsequent send() functions, and limits the remote sender for subsequent recv() functions. [...] Note that despite no connection being made, the term ``connected'' is used to describe a connectionless-mode socket for which a peer address has been set.

UDP 同样不是连接模式协议。特别地,它是一个数据报协议。如果你想要一对套接字,每个套接字都将另一个设置为对等套接字,那么你必须在两边都使用 connect() 。数据报没有服务器套接字的概念,在连接套接字工厂的意义上,即使有对等集,UDP 套接字仍然可以与其他端点通信。

如果你想用 UDP 模拟服务器套接字,那么你需要从一个侦听众所周知端口的套接字开始。客户端将向该端口发送一条消息,并期望服务器建立一个 new,在不同端口上的单独套接字作为其伪连接的末端。服务器将从该套接字作出响应,告诉客户端它正在侦听哪个端口。

您可能希望使用这些初始消息的内容来确认每一方的意图并确保服务器的初始响应与预期的“连接请求”正确配对。例如,客户端的初始消息可能是“CONNECT ”,而服务器的初始响应是“ACCEPTED ”。每个中的关键字确认消息的意图,匹配的 UUID(或其他密钥)允许客户端将服务器响应与正确的连接请求相匹配。

您还必须知道 UDP 是一种不可靠的协议,但是,您必须准备好适应这一点。 UDP 数据报可能会被丢弃或丢失,并且它们的接收顺序可能与发送顺序不同。这是它如何实现比 TCP 更好的吞吐量的部分原因。如果你需要克服这些特性,那么你 可以 通过在 UDP 之上实现自己的更高级别的协议来做到这一点,但在这一点上你可能比刚刚使用 TCP 更糟首先。