Лучший способ дождаться, пока данные TcpClient станут доступны?

while (TcpClient.Client.Available == 0)
{
    Thread.Sleep(5);
}

Есть лучший способ сделать это?


person Jader Dias    schedule 21.07.2009    source источник


Ответы (1)


Абсолютно! Просто вызовите Read(...) в потоке. Это будет блокироваться до тех пор, пока данные не будут доступны. Если вам действительно необходимо использовать TcpClient напрямую, я обычно делаю все возможное в потоке. Если вы хотите использовать сокет, просто вызовите Receive(byte[]), который будет блокироваться до тех пор, пока данные не будут доступны (или сокет не будет закрыт).

Теперь, если вы не хотите блокировать, вы можете использовать Stream.BeginRead или Socket.BeginReceive для асинхронной работы. (Или ReadAsync в .NET 4.5.)

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

person Jon Skeet    schedule 21.07.2009
comment
@Jader: Только если он передает текст с другого конца, и он закроет сокет, когда закончит отправку. Например, не подходит для соединений HTTP KeepAlive. - person Jon Skeet; 21.07.2009
comment
@tig: если ReadLine возвращает значение null, это означает, что поток был закрыт и доступных строк больше нет. Это действительно звучит так, как будто вы должны посмотреть, что происходит на сетевом уровне, например. с Wireshark. - person Jon Skeet; 04.09.2013
comment
Я думаю, что они хотели, скорее, одну из Socket.Poll() или Socket.Select(), и, поскольку у TcpClient нет функций, в идеале его не следует использовать. Блокирование чтения не является хорошей идеей, поскольку оно не позволяет указать промежуток времени для ожидания данных. - person Hi-Angel; 27.07.2015
comment
@Hi-Angel: Вы всегда можете установить TcpClient.ReceiveTimeout, если хотите... разве это не сделает то, о чем вы говорите? - person Jon Skeet; 27.07.2015
comment
@JonSkeet а, эти побочные эффекты ☺ - person Hi-Angel; 27.07.2015
comment
@Hi-Angel: Не уверен, что вы имеете в виду, но если он делает то, что требуется, я думаю, что это более простое решение, чем использование API более низкого уровня. (Черт возьми, мы даже не знаем, хочет ли OP тайм-аут...) - person Jon Skeet; 27.07.2015
comment
Просто чтобы добавить к ответу, есть также ReadAsync, доступный с .NET..... 4.5? - person Pluc; 24.09.2015
comment
@Pluc: добавил это. Я не собираюсь вдаваться во все подробности ожидания :) - person Jon Skeet; 24.09.2015
comment
В моем случае я пытаюсь захватить сообщение с неопределенной длиной и начальным/конечным символом, которое оно отправляет с интервалом 1 с с интервалом 0,1 с. Если я пытаюсь захватить всего одно сообщение целиком, а затем отправить его на анализ, я не понимаю, как бы я сделал это без Available. Так что, возможно, это не совсем бесполезно в моем случае. @ДжонСкит - person corylulu; 09.03.2018
comment
@Corylulu: вы бы сохранили буфер и читали столько, сколько могли, при каждом вызове. Затем вы заметите, когда у вас есть целое сообщение, и обработаете его, но сохраните все остальное, что все еще находится в буфере. Даже если сообщения отправляются с интервалом в 0,1 с, вы не должны предполагать, что то, что доступно для чтения, никогда не пересечет границу сообщения. - person Jon Skeet; 09.03.2018