Могу ли я установить тайм-аут для UdpClient в С#?

Мне интересно, могу ли я установить значение тайм-аута для метода получения UdpClient.

Я хочу использовать блочный режим, но поскольку иногда udp теряет пакет, моя программа udpClient.receive будет висеть там навсегда.

любые хорошие идеи, как я могу управлять этим?


person Jack    schedule 17.02.2010    source источник


Ответы (5)


То, на что ссылается Филип, вложено в сокет, который содержит UdpClient (UdpClient.Client.ReceiveTimeout).

Вы также можете использовать для этого асинхронные методы, но вручную заблокировать выполнение:

var timeToWait = TimeSpan.FromSeconds(10);

var udpClient = new UdpClient( portNumber );
var asyncResult = udpClient.BeginReceive( null, null );
asyncResult.AsyncWaitHandle.WaitOne( timeToWait );
if (asyncResult.IsCompleted)
{
    try
    {
        IPEndPoint remoteEP = null;
        byte[] receivedData = udpClient.EndReceive( asyncResult, ref remoteEP );
        // EndReceive worked and we have received data and remote endpoint
    }
    catch (Exception ex)
    {
        // EndReceive failed and we ended up here
    }
} 
else
{
    // The operation wasn't completed before the timeout and we're off the hook
}
person Brad Nabholz    schedule 17.02.2010
comment
Это было давно! Теперь это выглядит нормально. WaitOne также возвращает результат, который вы можете использовать, чтобы определить, истекло ли время ожидания. - person weston; 10.07.2014

Есть свойства SendTimeout и ReceiveTimeout, которые можно использовать в Socket из UdpClient.

Вот пример 5-секундного тайм-аута:

var udpClient = new UdpClient();

udpClient.Client.SendTimeout = 5000;
udpClient.Client.ReceiveTimeout = 5000;

...
person sep15ms    schedule 16.04.2011
comment
Это работает, только если вы выполняете синхронную отправку/получение. Для асинхронных вызовов вы можете использовать Task.Delay для создания собственного тайм-аута, например. Task.WhenAny(udpClient.ReceiveAsync(), Task.Delay(5000)); - person AJ Richardson; 31.05.2017
comment
Да, конечно! Как я пропустил это простое решение! Спасибо за ваш комментарий AJ! - person Jörgen Sigvardsson; 10.11.2017
comment
@AJRichardson хорошо, я не думаю, что это хороший способ, потому что, когда таймер -ask завершится, процесс возобновится, НО udpClient.ReceiveAsync() все еще будет ждать ... Я бы предложил что-то вроде: Task.WaitAny(new[] { udpClient.ReceiveAsync() }, waitTimeOutInMs); - person Ivandro Jao; 12.09.2020
comment
@IvandroJao Вы правы, хотя я не знаю, решит ли ваш код проблему. Похоже, вы должны закрыть сокет в случае тайм-аута: см. stackoverflow.com/a/12642359/1299394 - person AJ Richardson; 13.09.2020

На самом деле, похоже, что UdpClient не работает, когда дело доходит до тайм-аутов. Я попытался написать сервер с потоком, содержащим только Receive, который получил данные и добавил их в очередь. Я делал такие вещи в течение многих лет с TCP. Ожидается, что цикл блокируется на приеме до тех пор, пока не придет сообщение от запрашивающей стороны. Однако, несмотря на установку тайм-аута на бесконечность:

_server.Client.ReceiveTimeout = 0; //block waiting for connections
_server.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 0);

сокет отключается примерно через 3 минуты.

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

person Pierre    schedule 01.06.2012
comment
Я предполагаю, что внутренний тайм-аут составляет 200000 мс или около того? - person Christopher Stevenson; 23.04.2013

вы можете сделать так:

udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 5000);
person Elyas Nategh    schedule 29.08.2017

Существует свойство ReceiveTimeout, которое вы можете использовать.

person Filip Ekberg    schedule 17.02.2010
comment
ReceiveTimeout предназначен только для вызовов синхронизации (например, метод получения). - person Mauro Sampietro; 26.07.2018