UDP服务器和连接的套接字 [英] UDP server and connected sockets

查看:121
本文介绍了UDP服务器和连接的套接字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎是我在十年前在这里问过的问题...

[edit] Seems my question was asked nearly 10 years ago here...

为以下内容模拟accept() UDP(设置解复用的UDP套接字的时机问题)

...没有干净且可扩展的解决方案.我认为这可以通过支持UDP的listen()和accept()来方便地解决,就像现在的connect()一样. [/edit]

...with no clean and scalable solution. I think this could be solved handily by supporting listen() and accept() for UDP, just as connect() is now. [/edit]

在这个问题的后续行动中……

In a followup to this question...

可以绑定()并连接()UDP连接的两端

...是否有任何机制可以同时绑定()和连接()?

...is there any mechanism to simultaneously bind() and connect()?

我问的原因是出于可扩展性目的,多线程UDP服务器可能希望将新的会话"移到其自己的描述符中.目的是防止侦听器描述符成为瓶颈,类似于SO_REUSEPORT的基本原理.

The reason I ask is that a multi-threaded UDP server may wish to move a new "session" to its own descriptor for scalability purposes. The intent is to prevent the listener descriptor from becoming a bottleneck, similar to the rationale behind SO_REUSEPORT.

但是,具有新描述符的bind()调用将接管侦听器描述符的端口,直到进行connect()调用为止.这为进入数据报传递到新的描述符队列提供了机会的窗口,尽管时间很短.

However, a bind() call with a new descriptor will take over the port from the listener descriptor until the connect() call is made. That provides a window of opportunity, albeit briefly, for ingress datagrams to get delivered to the new descriptor queue.

对于希望使用DTLS的UDP服务器,此窗口也是一个问题.如果客户端重试,则可以恢复,但是不必这样做.

This window is also a problem for UDP servers wanting to employ DTLS. It's recoverable if the clients retry, but not having to would be preferable.

推荐答案

connect()不提供连接多路分解.

connect() on UDP does not provide connection demultiplexing.

connect()做两件事:

  1. 设置不接受目标地址(send()write()等)的传输功能的默认地址

  1. Sets a default address for transmit functions that don't accept a destination address (send(), write(), etc)

为传入的数据报设置过滤器.

Sets a filter on incoming datagrams.

重要的是要注意,传入的过滤器只是丢弃不匹配的数据报.它不会将它们转发到其他地方.如果有多个UDP套接字绑定到同一地址,则某些操作系统会为每个数据报选择一个(可能是随机的,也许是上次创建的)(多路分解完全中断),而某些操作系统会将所有数据报传送给所有它们(多路分解成功,但令人难以置信)效率低下).两者都是错误的事情".即使是一个允许您通过套接字选项在两种行为之间进行选择的操作系统,其运行方式也仍然与您想要的方式有所不同. bind()connect()之间的时间只是这种令人讨厌的行为难题中的最小部分.

It's important to note that the incoming filter simply discards datagrams that do not match. It does not forward them elsewhere. If there are multiple UDP sockets bound to the same address, some OSes will pick one (maybe random, maybe last created) for each datagram (demultiplexing is totally broken) and some will deliver all datagrams to all of them (demultiplexing succeeds but is incredibly inefficient). Both of these are "the wrong thing". Even an OS that lets you pick between the two behaviors via a socket option is still doing things differently from the way you wanted. The time between bind() and connect() is just the smallest piece of this puzzle of unwanted behavior.

要与多个对等方一起处理UDP,请在无连接模式下使用单个套接字.要让多个线程并行处理接收到的数据包,您可以

To handle UDP with multiple peers, use a single socket in connectionless mode. To have multiple threads processing received packets in parallel, you can either

    在处理数据的多个线程上
  • 调用recvfrom(这是有效的,因为数据报套接字保留消息边界,您永远不会使用诸如TCP之类的流套接字来执行此操作),或者
  • 在不执行任何处理的单个线程上调用recvfrom,仅将消息排队到负责处理该消息的线程.
  • call recvfrom on multiple threads which process the data (this works because datagram sockets preserve message boundaries, you'd never do this with a stream socket such as TCP), or
  • call recvfrom on a single thread, which doesn't do any processing, just queues the message to the thread responsible for processing it.

即使您的操作系统为您提供了基于指定的对等地址来分派传入UDP的选项(连接仿真),在OS内部进行分派仍不会比在服务器应用程序中进行分派有效,并且针对您的流量模式进行了调整的用户空间调度程序可能会比操作系统提供的一刀切"的调度程序具有更好的性能.

Even if you had an OS that gave you an option for dispatching incoming UDP based on designated peer addresses (connection emulation), doing that dispatching inside the OS is still not going to be any more efficient than doing it in the server application, and a user-space dispatcher tuned for your traffic patterns is probably going to perform substantially better than a one-size-fits-all dispatcher provided by the OS.

例如,DNS(DHCP)服务器将与许多不同的主机进行事务处理,几乎所有主机都在远程端的端口53(67-68)上运行.因此,基于远程端口的哈希将无用,您需要在主机上进行哈希.相反,支持Web应用程序服务器群集的缓存服务器将与少量主机和大量不同的端口进行事务处理.在这里,在远程端口上进行哈希处理会更好.

For example, a DNS (DHCP) server is going to transact with a lot of different hosts, nearly all running on port 53 (67-68) at the remote end. So hashing based on the remote port would be useless, you need to hash on the host. Conversely, a cache server supporting a web application server cluster is going to transact with a handful of hosts, and a large number of different ports. Here hashing on remote port will be better.

自己进行连接关联,不要使用套接字连接仿真.

Do the connection association yourself, don't use socket connection emulation.

这篇关于UDP服务器和连接的套接字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆