views:

248

answers:

2

Hi,

i use a UDP-socket for sending/receiving objects. I serialize the objects into a byte array send it and receive it with a client. But before i can receive i have to allocate a byte array. I must do it before and then handle the Socket.Receive()-methode the array. But my objects have a variable length. How can i discover the array-size?

Thank you

Edit: Here a example of my receive-methode:

BinaryFormatter bf = new BinaryFormatter();

public Object ReceiveUdpPacket()
        {
            byte[] objData = new byte[bufferSize];

            IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
            EndPoint ep = (EndPoint)ipep;
            MemoryStream ms = new MemoryStream();

            udpSocket.ReceiveFrom(objData, ref ep);

            ms.Write(objData, 0, objData.Length);
            ms.Seek(0, SeekOrigin.Begin);

            return (Object)bf.Deserialize(ms);
        }
A: 

The most typical method of doing this involves something along the lines of having the first few bytes of a data chunk be the chunk length.

So, for example, if your object size is always under 65k or there abouts, you could send the array size through the socket first as a short (Look at using the BitConverter class). The receiver would read the first chunk it receives into a buffer (probably one roughly the size of a nominal UDP packet, somewhere around 512 bytes), grab the first two bytes, convert them to a short, and set up the buffer for the object. It would then continue to read from the socket until that buffer is full, and pass that buffer off to the de-serializer.

This of course doesn't cover error handing and such, but it's the basic idea.

EDIT:

It's been awhile since I did anything with UDP in .Net, but something like this might work (In somewhat psuedocode)

var bigBuffer = new MemoryStream();

//This should be run in a thread
void UdpLoop()
{
   while(!done)
   {
      var buffer = udpClient.Receive();
      bigBuffer.Write(buffer,buffer.Length);
   }
}

void MessageProcessor()
{
   var messageLength = 0;
   while(!done)
   {
      if(bigBuffer.Length > 0 && messageLength == 0)
      {
         var lengthBytes = new byte[2];
         bigBuffer.Read(lengthBytes, 2);
         messageLength = BitConverter.ToInt16(lengthBytes); 
      }
      if(messageLength > 0 && bigBuffer.Length > messageLength)
      {
         var objectBuffer = new byte[messageLength];
         bigBuffer.Read(objectBuffer, messageLength);
         //Do deserialization here
      }
   }
}

That's the basic process, ignoring locking due to multiple threads (which you will have to deal with since Receive bocks), and reading and writing from different spots in the memory stream. Hopefully this is enough to get you going in the right direction.

Matt S
How can i grab the first two bytes? I only can read from the socket in one breath. If the buffer is not big enough i get a exception. It looks like this problem is normal with udp-sockets^^
This approach only works with connection-oriented sockets (e.g., TCP), not connectionless sockets (e.g., UDP). I can't speak to XNA. In .NET, though, if the message is bigger than the buffer, the buffer will be filled with the first part of the message, the rest of the message will be lost, and a `SocketException` will be thrown. You're gonna have to read the entire message at once, which requires a buffer big enough to accommodate the largest message you can possibly receive.
Matt Davis
Okay, i understand your approache. But there is a little problem. It looks like you put the result of the .Receive()-Methode in the stream, but this result is not the object/the bytes, the result is a Int (bytes received). Is that intendes? The way you handle with the .Receive-Method is this: byte[] objData = new byte[bufferSize]; udpSocket.ReceiveFrom(objData, ref ep); I will put this example in my question.
A: 

Chances are you're dealing with typical UDP packets which are limited to a size of 64k, or 65535 bytes. Allocate a 64k-byte array and pass that to the Receive() function. Assuming a typical socket implementation, the Receive() function will return the number of bytes that were actually received.

Matt Davis