По каким причинам NetworkStream.Read зависает / блокируется? - PullRequest
8 голосов
/ 05 августа 2011

Документация MSDN, кажется, предполагает, что NetworkStream.Read всегда будет возвращаться немедленно. Если данные не найдены, возвращается 0. Однако у меня есть некоторый код, который в настоящее время развернут, но только в некоторых случаях (и я еще не выяснил, какие из них), NetworkStream.Read зависает. Вот трассировка стека, которую мне удалось собрать из файла дампа

00000000705ae850 000007fef784f60d DomainBoundILStubClass.IL_STUB(IntPtr, Byte*, Int32, System.Net.Sockets.SocketFlags)
00000000705ae930 000007fef785c930 System.Net.Sockets.Socket.Receive(Byte[], Int32, Int32, System.Net.Sockets.SocketFlags, System.Net.Sockets.SocketError ByRef)
00000000705ae9b0 000007ff004eb668 System.Net.Sockets.NetworkStream.Read(Byte[], Int32, Int32)
00000000705aea40 000007fef784e6ae MySocketStuff.SocketConnectCallback(System.IAsyncResult)
00000000705aeb20 000007fef84f2bbb System.Net.LazyAsyncResult.Complete(IntPtr)
00000000705aeb90 000007fef7853c7b System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
00000000705aebe0 000007fef784e5d3 System.Net.ContextAwareResult.Complete(IntPtr)
00000000705aec40 000007fef7d027f9 System.Net.LazyAsyncResult.ProtectedInvokeCallback(System.Object, IntPtr)
00000000705aeca0 000007fef8b9815e System.Net.Sockets.Socket.ConnectCallback()
00000000705aed20 000007fef93e14c2 System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(System.Object, Boolean)

Я заметил, что NetworkStrea.Read на самом деле вызывает Socket.Receive, который, насколько я понимаю, может блокировать. Я просто не знаю, почему иногда он блокируется, а иногда нет.

Ответы [ 4 ]

26 голосов
/ 05 августа 2011

Раздел Замечания документации для NetworkStream.Read вводит в заблуждение.Он говорит:

Этот метод считывает данные в параметр буфера и возвращает количество успешно прочитанных байтов. Если данные для чтения недоступны, метод Read возвращает 0. Операция Read читает столько данных, сколько доступно, вплоть до количества байтов, указанного параметром size.Если удаленный хост завершает соединение и все доступные данные получены, метод Read завершается немедленно и возвращает ноль байтов.

В нем должно быть указано:

ThisМетод считывает данные в параметр буфера и возвращает количество успешно прочитанных байтов. Если данные для чтения недоступны, метод Read блокируется до тех пор, пока данные не станут доступны или соединение не будет закрыто. Операция Read читает столько данных, сколько доступно, вплоть до количества байтов, указанного параметром size.,Если удаленный хост завершает соединение и все доступные данные получены, метод Read завершается немедленно и возвращает ноль байтов.

7 голосов
/ 05 августа 2011

Иногда в буфере сокета уже есть данные, а иногда нет, предположительно.

Одной из распространенных причин просмотра блока NetworkStream является то, что каждая сторона соединения ожидает другую сторонузакрывать.Например, если вы устанавливаете соединение HTTP 1.1 keep-alive, но по-прежнему выполняете способ чтения контента «чтение до закрытия соединения».

3 голосов
/ 13 октября 2015

Одной из распространенных ошибок при работе с NetworkStream является отправка незаконченных команд с помощью метода Write, что приводит к последовательному Read зависанию вызова.

См. Приведенный ниже пример, который пытается отправить имя пользователя на открытый порт FTP. Ожидается ответ типа 331. Укажите пароль , но метод Read зависает:

var request = Encoding.ASCII.GetBytes("user [username]");
networkStream.Write(request, 0, request.Length);
var streamReader = new StreamReader(networkStream);
var response = streamReader.ReadLine(); // <-- hangs

Волшебное решение состоит в том, чтобы заменить первую строку следующим текстом:

var request = Encoding.ASCII.GetBytes("user [username] \r\n");

Просто добавив фразу \ r \ n в конце команды, все начнет работать, как и ожидалось.

0 голосов
/ 05 августа 2011

Если данные для чтения недоступны, метод чтения блокируется, пока данные не станут доступны. Подумайте об использовании функций Async Socket, если вы не хотите блокировать. http://msdn.microsoft.com/en-us/library/bbx2eya8.aspx

...