接收UDP消息而无需分配新的缓冲区
尝试使用udpclient.receive
时,我注意到它只是返回字节数组。这是否为每个数据包分配一个新的缓冲区?据我所知,为每个收到的数据包分配一个新的字节阵列对性能和内存使用情况不利。为了在使用TCP时解决同样的问题,我使用Arraypool租用缓冲区。但是我该如何使用UDP做到这一点?
我考虑过使用相同的方法(例如使用TCP),只是使用插座,但是UDP不是基于流的,因此方法毫无意义(我不知道一个数据包将是多大的,我无法从类似的流中继续阅读在TCP中)。
tl; dr:
在接收UDP数据包时,我如何保存性能?
When trying to use UdpClient.Receive
I noticed that it just returns a byte array. Does this allocate a new buffer for every packet? As far as I know, allocating a new byte array for every received packet is bad for performance and memory usage. To get around that same problem when using Tcp, I used an ArrayPool to rent the buffers. But how would I do that with Udp?
I thought about using the same method like with Tcp and just using a socket, but udp is not stream based and therefore that approach makes little sense (I don't know how big one packet will be and I cannot continually read from a stream like in Tcp).
TL;DR:
How do I save performance when receiving UDP packets while still always receiving the full packet?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
通常,是的。
在内部,
udpclient
使用固定尺寸的字节[65536]
数组来读取每个数据包。如果接收到的数据包正是如此大小,则将内部缓冲区按原样返回。但是,如果接收到的数据包小于该大小,通常是这种情况,则将其分配一个新的byte []
的实际数据包大小,将内部缓冲区的数据复制到该新数组中,并且然后返回。可以确定下一个数据包的实际尺寸而不从插座队列中提取数据包。 WinSock的
recvFrom()
功能具有MSG_PEEK
为此目的标志。udpclient.receive()
不支持该标志,但是udpclient
的基础socket
在其rechodffrom()方法,例如:
尽管
socket.receivefrom()
的确允许0长度byte []
array(它将传递空指针和0个缓冲区长度到Winsock的<代码> recvFrom()),我不确定的是socket.receivefrom()
实际上会返回下一个数据包大小,或者是否会抛出socketExecception
如果您尝试使用byte []
数组小于实际数据包(我不确定recvfrom() byte []
数组>报告使用msg_peek
flag使用 wsaemsgsize 错误。为了避免这个潜在的问题,请继续阅读...
我建议您只尝试使用单个64K
byte []
array(例如udpclient
在内部使用),因为UDP数据包永远不会超过该大小。只需直接使用udpclient.client.client.receivefrom()
而不是使用udpclient.receive()
,例如:这样,您可以重复使用单个
byte [ ]
多个读数的数组(就像udpclient
在内部使用)。Typically, yes.
Internally,
UdpClient
uses a fixed-sizedbyte[65536]
array to read each packet. If a received packet is exactly that size, the internal buffer is returned as-is. However, if the received packet is less than that size, which is usually the case, then it allocates a newbyte[]
of the actual packet size, copies the internal buffer's data into that new array, and then returns it.It is possible in the Winsock API to determine the next packet's actual size without extracting the packet from the socket's queue. Winsock's
recvfrom()
function has aMSG_PEEK
flag for that purpose.UdpClient.Receive()
does not support that flag, however theUdpClient
's underlyingSocket
does in itsReceiveFrom()
method, eg:Although
Socket.ReceiveFrom()
does allow a 0-lengthbyte[]
array (it will pass a NULL pointer and 0 buffer length to Winsock'srecvfrom()
), what I'm not sure about is whetherSocket.ReceiveFrom()
will actually return the next packet size, or if it will throw aSocketException
if you try to peek into the queue using abyte[]
array that is smaller than the actual packet (as I am not sure whether or notrecvfrom()
reports aWSAEMSGSIZE
error when theMSG_PEEK
flag is used).To avoid this potential issue, keep reading ...
Rather then trying to pool arrays, I would suggest you simply use a single 64K
byte[]
array (likeUdpClient
does internally), since UDP packets will never exceed that size. Simply useUdpClient.Client.ReceiveFrom()
directly instead of usingUdpClient.Receive()
, eg:This way, you can re-use a single
byte[]
array for multiple reads (just asUdpClient
does internally).