5

This is maybe a stupid question, but since I am relatively new to UDP here it goes... If I am having two separate byte arrays that I need the receiving side to get as one big array, for example:

byte[] Array1 = {1,1,1}
byte[] Array2 = {2,2,2}

Can I avoid having to create a buffer and copy each array into it, and then send that buffer, like this:

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);

Because if the two are big, and data rate is high, copying uses up much system resources... So can I somehow tell the udpClient that I am starting the UDP fragmentation, and then do like this:

udpClient.ImStartingOneBigDatagram();

udpClient.Send(Array1, Array1.Length);
udpClient.Send(Array2, Array2.Length);

udpClient.ThatsAllFolks();

And be sure that the receiving side would get:

byte[] recv = {1,1,1,2,2,2}

I am using C# for this, and I dont need to use UdpClient, I was just making my point.

Matt
  • 74,352
  • 26
  • 153
  • 180
Cipi
  • 11,055
  • 9
  • 47
  • 60
  • With UDP, you can't even be sure that the receiving end will even receive them, never mind whether they will be received in order. Datagrams are either received in whole or not received at all though. The receiving end will not combine several datagrams in a single Receive. – Mark H Jun 30 '11 at 17:40
  • @Mark H: What about UDP fragmentation? There is the MF (More Fragments) flag in UDP packet, if I could set it to 1 on first packet, and to 0 on last one, that would be the same as the IP performed fragmentation of UDP pakcet... no? – Cipi Jun 30 '11 at 17:51
  • 1
    Cipi, the MF flag is in the IP packet, not UDP! – user703016 Jun 30 '11 at 18:08
  • Oh yeah, IP, sorry... I meant that... Can I set that flag from C#?? – Cipi Jul 01 '11 at 09:09
  • I don't see any "wrong in this case". You have one Send, and one Receive. – Ben Voigt Sep 30 '14 at 20:59
  • BenVoigt: idea was that client sends 10 little parts of a greater buffer, and the receiving side read reads all those in 1 read (not 10 reads). – Cipi Jan 14 '15 at 11:38
  • @Cipi: I know this was posted a long time ago, but I've edited out the updated-solution out of the question. Consider posting it as an actual answer if you feel it has value. – Matt Jun 24 '15 at 11:49

2 Answers2

2

Yes, you can split any data block into two parts and send it out as two separate UDP packets. However, UDP does not guarantee delivery, so one of the pieces may go missing in transit. What will you do if the recipient receives only half the message? Throw it away, obviously, but something to keep in mind with UDP.

So, to answer the last part of your question "And be sure that the receiving side would get..." the answer is no. You're using UDP, so you can't be sure the receiving side would get anything.

If you are wanting to break up the send into multiple chunks for your convenience rather than for network packet size concerns, you can certainly write your own wrapper class that sits above the UDPclient and accepts multiple chunks of data via a Send method call and only sends all the data to the udpclient.Send() when you call .ThatsAllFolks on your wrapper class. But that's not going to reduce memory overhead since the wrapper has to accumulate the data in memory before the Big Send. This wrapper would just be a cosmetic convenience for your client code.

dthorpe
  • 35,318
  • 5
  • 75
  • 119
  • Ok, I am willing to take that chance... But how to do it in C#?! If I send 2 arrays by calling `Send()` 2 imes, receiving side must call `Receive()` two times to get them, but I want them to arrive as one packet, and I don't care if one of them is lost... :P – Cipi Jun 30 '11 at 17:47
  • AFAIK, if you send twice, you have to receive twice. UDP's don't coalesce. – dthorpe Jun 30 '11 at 18:20
  • Think of it this way: When you call udpclient.Send(), the data is put on the wire immediately. When you call .Send() the second time, the first UDP is gone, so the 2nd send sends a 2nd UDP. – dthorpe Jun 30 '11 at 18:24
  • Ok, so as I can see, there is no way of doing this... What about the MF flag of the IP protocol? Can it be set "by user" or it is network automated...? – Cipi Jul 01 '11 at 09:10
  • I think you will have the same issue with a TCP Send(), because of the semantics that are baked in. To do what you're asking for, you need to operate at a lower level where there is less semantic support / less being done automatically for you behind the scenes. I don't know offhand if you can manipulate the IP stack at that level from C#, or if you need to switch to something else like sockets. – dthorpe Jul 01 '11 at 16:22
  • A metaphor to help visualize what you're fighting against: Send() has a built in semantic of take the data and put it on the wire wrapped in a packet that says "this is a complete packet". Think of an automatic door at the supermarket: it opens for you, and then it closes. It's semantic is open *and* close. What you're asking for is a way to open but not close the door, and that runs counter to the purpose of Send(). You need something other than Send, something more like "Put" that doesn't imply completion. – dthorpe Jul 01 '11 at 16:28
2

Use the equivalent of Win32 API's WSASendMsg:

public int Send(
    IList<ArraySegment<byte>> buffers,
    SocketFlags socketFlags,
    out SocketError errorCode
)

http://msdn.microsoft.com/en-us/library/ms145161.aspx

But ultimately this is premature optimisation, if you perform some testing you will see that to use I/O scatter gather arrays you need at least 9KB of data to get performance improvement. For small buffers, i.e. less than a page size (4KB on x86) it is faster to build a contiguous buffer yourself before passing to the socket API.

Steve-o
  • 12,678
  • 2
  • 41
  • 60