1


I am doing some basic Socket messaging. I have a routine that works well but there is a problem under load.

I'm using UDP to do a connectionless SendTo to basically do a ping-like operation to see if any of my listeners are out there on the LAN. Ideally I would just use the broadcast address, but Wireless routers don't seem to relay my broadcast. My work around is to iterate through all IPs on the Subnet and send my data gram to each IP. The other PCs are listening and if they get the message they will reply and that is how I get Peers to find each other. Here is the code that is in the loop which sends the data gram to each IP in the subnet.

            string msgStr = "some message here...";
            byte[] sendbuf = Encoding.ASCII.GetBytes(msgStr);

            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            socket.Blocking = true;
            socket.SendTo(sendbuf, remoteEndPt);
            //socket.Close();

This works, but when the Subnet range is large, say 255.255.0.0 (meaning ~60,000 IPs to iterate through) I will eventually get a SocketException with error code "10022", meaning "Invalid Argument". This tends to happen after ~10,000 or so successful sends then I start to see this error. Also, the router I use at work handles it and is presumably a high powered router, but the cheap-o one in my lab is the one that produces the error.

If I put in a wait time after catching the SocketException and before resuming the loop it will typically recover but eventually I'll get the error again.

I think what is happening is that the buffer on the router gets full and I cannot send anymore data. The higher quality one at work can handle it but the cheap-o one gets bogged down. Does that sound plausible?

A couple questions:

1) When using SendTo in a connectionless manner, do I need to call Close() on my Socket?

I've haven't seen any benefit in calling Close(), but when I do call Close() it severely slows down my iteration (I have it commented out above because it does slow things down a lot). Does this make sense?

2) Is there a way for me to tell I should wait before trying to send more data? It doesn't seem right to just catch the Exception which I still don't know what the cause of it is.

Thanks, J.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
JayDee
  • 123
  • 1
  • 10

1 Answers1

2

I am not sure that is the router only but I suspect that you are also running into some limit in the OS...

Any reason you are creating the Socket every time you send ? Just reuse it...

Anyways according to http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx it is a good idea to call Shutdown() and then Close() on the Socket... perhaps not with every send but every 255 IPs or so...

Checkout UdpClient - that could make implementation easier / more robust

EDIT - as per comment:

IF you want a Socket reuse "cache"... this for example would make sure that a specific Socket is only used every 256 checks...

// build/fill your Socket-Queue for example in the con
class SocketExample
{
    Queue<Socket> a = new Queue<Socket>();
    SocketExample ()
    {
        int ii = 0, C = 256;
        for (ii = 0; ii < C; C++)
        {
            a.Enqueue (new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp));
        }
    }

    // in your function you just dequeue a Socket and use it, 
    // after you are finished you enqueue it
    void CheckNetIP (some parameters...)
    {
        Socket S = a.Dequeue();
        // do whatever you want to do...
        // IF there is no exception
        a.Enqueue(S); 
    }
}
Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
Yahia
  • 69,653
  • 9
  • 115
  • 144
  • As I understand it Shutdown is for Connected Sockets, in my case I'm using Connectionless. Correct me if I'm wrong. As for UdpClient, I've tried that too with the same result. I believe that UdpClient is a convenience wrapper around the Socket implementation I'm using, so it wouldn't, and didn't, make a difference using UdpClient vs. what I have already. – JayDee Aug 13 '11 at 16:43
  • true `Shutdown` is not needed with UDP, `Close` still applies... did you try my suggestion ? – Yahia Aug 13 '11 at 16:48
  • As I understand it Shutdown is for Connected Sockets, in my case I'm using Connectionless. As for UdpClient, I've tried that too with the same result. I believe that UdpClient is a convenience wrapper around the Socket implementation I'm using, so it wouldn't, and didn't, make a difference. Correct me if I'm wrong! I agree some Socket reuse is probably the correct approach. I did test it using only 1 Socket, reused every time and that slowed things way down. So, perhaps a better reuse strategy is going to be the answer. Do you know of any good samples with a Socket Pool or reuse? Thanks! – JayDee Aug 13 '11 at 16:50
  • sorry comment needed edit, but you only have 5 minutes to submit the edit. Please excuse the mess. Thanks! – JayDee Aug 13 '11 at 16:51
  • thanks, the socket re-use was the key. The simple way to get re-use with the Queue is working great. The program does slow down as the socket buffers get full, but it never errors so this is a great solution. – JayDee Aug 15 '11 at 21:31
  • I know this is old but wouldn't the Queue just delay the error from happening? Instead of in 255 IP addresses its now 255 * Queue.Count IP addresses? Just seems like this is making it less likely at the cost of the overhead of creating 256 Sockets instead of just doing a cycle of it after X amount of use? – James May 03 '17 at 00:24