C # Socket.SendTo в цикле в конечном итоге вызывает SocketException (зависит от маршрутизатора) - PullRequest
1 голос
/ 13 августа 2011


Я делаю некоторые базовые сообщения Socket. У меня есть подпрограмма, которая работает хорошо, но есть проблема под нагрузкой.

Я использую UDP для выполнения SendTo без установления соединения, чтобы в основном выполнить операцию, подобную ping, чтобы проверить, есть ли кто-нибудь из моих слушателей в локальной сети. В идеале я бы просто использовал широковещательный адрес, но беспроводные маршрутизаторы, похоже, не передают мою широковещательную рассылку. Моя работа заключается в том, чтобы перебирать все IP-адреса в подсети и отправлять грамм данных на каждый IP-адрес. Другие ПК слушают, и если они получат сообщение, они ответят, и именно так я заставлю Пиров найти друг друга. Вот код в цикле, который отправляет грамм данных каждому IP в подсети.

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

Это работает, но когда диапазон подсетей велик, скажем, 255.255.0.0 (что означает ~ 60 000 IP-адресов для итераций), я в конечном итоге получу исключение SocketException с кодом ошибки "10022", что означает "Недопустимый аргумент". Обычно это происходит после ~ 10000 или около того успешных отправок, и я начинаю видеть эту ошибку. Кроме того, маршрутизатор, который я использую на работе, обрабатывает его и, вероятно, является мощным маршрутизатором, но дешевый в моей лаборатории - тот, который выдает ошибку.

Если я добавлю время ожидания после перехвата SocketException и до возобновления цикла, оно, как правило, восстановится, но в конце концов я получу ошибку снова.

Я думаю, что происходит то, что буфер на маршрутизаторе переполнен, и я больше не могу отправлять данные. Более качественный на работе может справиться с этим, но дешевый - увязнет. Это звучит правдоподобно?

Пара вопросов:

1) При использовании SendTo в режиме без установления соединения мне нужно вызывать Close () на моем Socket?

Я не видел никакой пользы в вызове Close (), но когда я вызываю Close (), это сильно замедляет мою итерацию (у меня это закомментировано выше, потому что это сильно замедляет работу). Имеет ли это смысл?

2) Можно ли мне сказать, что мне следует подождать, прежде чем пытаться отправить больше данных? Кажется неправильным просто поймать Исключение, которое я до сих пор не знаю, в чем причина.

Спасибо, J.

1 Ответ

2 голосов
/ 13 августа 2011

Я не уверен, что это только маршрутизатор, но я подозреваю, что вы также работаете с некоторым пределом в ОС ...

По какой причине вы создаете Socket при каждой отправке?Просто используйте его ...

В любом случае, согласно http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx, неплохо было бы позвонить Shutdown(), а затем Close() на Socket ... возможно, не при каждой отправке, нокаждые 255 IP-адресов или около того ...

Оформление заказа UdpClient - это может сделать реализацию проще / надежнее

РЕДАКТИРОВАТЬ - согласно комментарию :

ЕСЛИ вам нужен «кэш» повторного использования сокетов ... это, например, будет гарантировать, что определенный сокет используется только каждые 256 проверок ...

// 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); 
    }
}
...