UDP - 我可以发送两个数据报部分,并让接收端将它们合并为一个吗?
Posted
技术标签:
【中文标题】UDP - 我可以发送两个数据报部分,并让接收端将它们合并为一个吗?【英文标题】:UDP - Can I send two datagram parts, and make the receiving end combine them into one? 【发布时间】:2011-09-26 04:32:39 【问题描述】:这可能是一个愚蠢的问题,但由于我对 UDP 比较陌生,所以它会出现......如果我有两个单独的字节数组,我需要接收端作为一个大数组来获取,例如:
byte[] Array1 = 1,1,1
byte[] Array2 = 2,2,2
我是否可以避免创建缓冲区并将每个数组复制到其中,然后发送该缓冲区,如下所示:
byte[] Buffer= new byte[Array1.Length + Array2.Length];
Buffer.BlockCopy(Array1, 0, Buffer, 0, Array1.Length);
Buffer.BlockCopy(Array2, 0, Buffer, Array1.Length, Array2.Length);
udpClient.Send(Buffer, Buffer.Length);
因为如果两者都很大,而且数据率很高,复制会占用很多系统资源... 那么我能否以某种方式告诉 udpClient 我正在启动 UDP 分片,然后这样做:
udpClient.ImStartingOneBigDatagram();
udpClient.Send(Array1, Array1.Length);
udpClient.Send(Array2, Array2.Length);
udpClient.ThatsAllFolks();
并确保接收方会得到:
byte[] recv = 1,1,1,2,2,2
我为此使用 C#,我不需要使用 UdpClient
,我只是在说明我的观点。
【问题讨论】:
使用UDP,你甚至无法确定接收端是否会接收它们,更不用说它们是否会按顺序接收。数据报要么全部接收,要么根本不接收。接收端不会在一个 Receive 中合并多个数据报。 @Mark H:UDP 分片呢? UDP数据包中有MF(更多片段)标志,如果我可以在第一个数据包上将其设置为1,在最后一个数据包上设置为0,那将与IP执行的UDP pakcet分片相同......不是吗? Cipi,MF标志在IP包里,不是UDP! 哦,是的,IP,抱歉……我的意思是……我可以从 C# 中设置那个标志吗?? 我没有看到任何“在这种情况下有错误”。您有一个发送和一个接收。 【参考方案1】:使用相当于 Win32 API 的 WSASendMsg
:
public int Send(
IList<ArraySegment<byte>> buffers,
SocketFlags socketFlags,
out SocketError errorCode
)
http://msdn.microsoft.com/en-us/library/ms145161.aspx
但归根结底,这是过早的优化,如果您执行一些测试,您会发现要使用 I/O 分散收集数组,您至少需要 9KB 的数据才能获得性能提升。对于较小的缓冲区,即小于 page size(x86 上为 4KB),在传递给套接字 API 之前自己构建一个连续的缓冲区会更快。
【讨论】:
收集发送正是问题所在,完美答案。 WOOOOOOOOOOOOOOOOOORKSSSSS!!!!!!!!!!!!! xDDD 请稍后检查我更新的问题...谢谢老兄! :D【参考方案2】:是的,您可以将任何数据块分成两部分并将其作为两个单独的 UDP 数据包发送出去。但是,UDP 不保证交付,因此其中一件可能会在运输过程中丢失。如果收件人只收到一半的消息,你会怎么做?显然,把它扔掉,但使用 UDP 时要记住一些事情。
因此,要回答您问题的最后一部分“并确保接收方会得到...”,答案是否定的。您使用的是 UDP,因此您无法确定接收方会得到什么。
如果您想为了方便而不是考虑网络数据包大小而将发送分成多个块,您当然可以编写自己的包装类,它位于 UDPclient 之上并通过 Send 方法调用接受多个数据块并且仅当您在包装类上调用 .ThatsAllFolks 时将所有数据发送到 udpclient.Send() 。但这不会减少内存开销,因为包装器必须在大发送之前将数据累积在内存中。这个包装器只是为您的客户端代码提供美观的便利。
【讨论】:
好吧,我愿意抓住这个机会......但是如何在 C# 中做到这一点?!如果我通过调用Send()
2 次发送2 个数组,接收方必须调用Receive()
两次才能获取它们,但我希望它们作为一个数据包到达,我不在乎其中一个是否丢失.. . :P
AFAIK,如果您发送两次,则必须接收两次。 UDP 不合并。
这样想:当您调用 udpclient.Send() 时,数据会立即传输到网络上。当您第二次调用 .Send() 时,第一个 UDP 消失了,因此第二次发送发送了第二个 UDP。
好的,所以我可以看到,没有办法这样做...... IP协议的MF标志呢?可以“由用户”设置还是网络自动化...?
我认为 TCP Send() 会遇到同样的问题,因为其中包含语义。要执行您的要求,您需要在较低级别进行操作语义支持较少/幕后自动为您完成的较少。我不知道您是否可以从 C# 操作该级别的 IP 堆栈,或者您是否需要切换到其他东西,例如套接字。以上是关于UDP - 我可以发送两个数据报部分,并让接收端将它们合并为一个吗?的主要内容,如果未能解决你的问题,请参考以下文章