Implementing Accept for UDP



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

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

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

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

不管怎样,如果有其他方法可以解决接受的问题,或者克隆套接字,我很想知道!非常感谢。

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

然而,你有一个更大的问题。如果你在同一个端口上打开了多个UDP套接字,并且单播数据包进入,那么这些套接字中只有一个会接收到它你无法准确预测它会是哪个;"倾听";插座和多个";"已接受";UDP连接的套接字无法工作。

您的程序需要有一个单独的套接字来处理所有传入的数据包,并根据发送方对其进行多路复用,可能有一个线程要接收,每个客户端有一个螺纹,但请先在没有螺纹的情况下尝试。

编辑:

考虑到使用连接的UDP套接字,看起来您可以有一个未连接的套接字作为侦听器,并为每个要与之交谈的远程端点提供一个连接的套接字。由于没有克隆函数,这意味着您为处理不同端点而创建的任何新套接字在创建套接字和对该套接字调用connect之间都将短暂地处于未连接状态。在这段时间内,与连接的套接字不相关联的传入分组可以到达"套接字";听众";或者它可以在连接之前到达这个新插座。您需要在应用程序中处理这种情况,最有可能的方法是让连接的套接字丢弃未知数据包,并让客户端重试其初始";"连接";直到他们接收到响应。

您写道,

真正的问题是udp提供了"连接",但没有"接受">

,但不是,真正的问题是UDP不是一个面向连接的协议。正如connect()的POSIX规范所解释的:

如果发起套接字不是连接模式,则connect()应设置套接字的对等地址,则不进行任何连接。对于SOCK_DGRAM套接字,对等地址标识所有数据报的位置在随后的send()函数上发送,并限制远程发件人用于随后的CCD_ 10功能。[…]注意,尽管没有建立连接,术语"已连接"用于描述已为其设置对等地址的无连接模式套接字。

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

如果你想用UDP模拟服务器套接字,那么你需要从一个在已知端口上侦听的套接字开始。客户端将向该端口发送消息,并期望服务器在不同端口上建立一个新的独立套接字,以结束伪连接。服务器会从那个套接字做出响应,告诉客户端它正在监听哪个端口

您希望使用这些初始消息的内容来确认每一方的意图,并确保服务器的初始响应与预期的"消息"正确配对;连接请求";。例如,也许客户端的初始消息是";CONNECT<PER-CONECTION-UUID>";,并且服务器的初始响应是"0";已接受<客户端-连接-UUID>";。每个关键字中的关键字都确认了消息的意图,并且匹配的UUID(或某些其他关键字)允许客户端将服务器响应与正确的连接请求相匹配。

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

最新更新