size of the next queued datagram - UDP
Asked Answered
H

2

6

I am using System.Net.Sockets Socket class to receive UDP datagrams. I wanted to know the exact length of the datagram received in order to check the validity of the datagram.

Socket.Receive(Byte()) method documentation says:

If you are using a connectionless Socket, Receive will read the first queued datagram from the destination address you specify in the Connect method. If the datagram you receive is larger than the size of the buffer parameter, buffer gets filled with the first part of the message, the excess data is lost and a SocketException is thrown.

Socket.Available property gives the total of bytes available to be read, This is sums up the size of all queued datagrams.

Is there a way I can find out the size of the next datagram?

public static void Receive()
{
    Byte[] buf, discardbuf;
    const int paklen = 32;                  //correct packet length
    int l;

    buf = new Byte[paklen];
    discardbuf = new Byte[4096];

    while (rcv_enable)
    {
        l = soc.Available;
        if (l == 0) continue;
        if (l == paklen) soc.Receive(buf);  //receive the correct packet
        else soc.Receive(discardbuf);       //discard otherwise
        Thread.Sleep(200);
        Console.WriteLine("Received {0}", l);
    };
}
Hoskins answered 10/12, 2011 at 18:47 Comment(0)
R
3

I'm going to assume that you've developed your own protocol and are expecting datagrams of a pre-known size and you want to guard yourself against rogue packets.

Since performance seems to be an issue and you want to avoid exceptions I'd have a look at the overload of Receive which returns the raw socket error instead of throwing exceptions. The MSDN documentation does (incorrectly?) state that this method too will throw an exception but I don't think that is the case. It's definitely worth a try.

SocketError error;
byte[] buffer = new byte[512]; // Custom protocol max/fixed message size
int c = this.Receive(buffer, 0, buffer.Length, SocketFlags.None, out error);

if (error != SocketError.Success)
{
    if(error == SocketError.MessageSize)
    {
        // The message was to large to fit in our buffer
    }
}

Use a buffer of a pre-known sane size and use the overload to check the SocketError error code in order to determine whether or not the read succeeded or if you sholud drop the package.

If, however your own protocol can send datagrams of unknown sizes up to the limit of the maximum datagram size you have no choice other than allocating a buffer large enough to fit the largest packet (65k) (you could use buffer pooling to avoid memory issues depending on your code).

Also check out the SocketFlags enum, it contains some members which may be of interest to you such as the Partial and Peek members.

Riess answered 10/12, 2011 at 21:37 Comment(1)
Perfect! This overload does the job and no exception is thrown. It seems, MSDN Documentation is incorrect. Thanks. -BTW I couldn't find any relevant example for SocketFlags enum in MSDN.Hoskins
S
2

Why not just check the return value from Receive? im quite sure each call will return one datagram.

Sunbeam answered 10/12, 2011 at 19:14 Comment(2)
It will work, but I always need to read the data into a bigger buffer. Otherwise, if the buffer is smaller than the datagram size, Receive() throws the exception Error Code: 10040 A message sent on a datagram socket was larger than the internal message buffer or some other network limit, or the buffer used to receive a datagram into was smaller than the datagram itself --actually this is a high performance code, exceptions are too expensive to throw and handleHoskins
Ah ok, unfortunately im no .NET expert but one solution could be figure out the maximum MTU of all interfaces your going to receive datagrams on. Another solution is to hardcode the buffer to 65535 bytes as that is the maximum UDP datagram size (16 bit length field), the actual practical maximum is a bit smaller, 65535 - IP-header - UDP-header.Sunbeam

© 2022 - 2024 — McMap. All rights reserved.