.NET сокет блокирует чтение до тех пор, пока не станет доступно X байтов? - PullRequest
3 голосов
/ 22 июля 2011

Предположим, у меня есть простой протокол, реализованный через TCP, где каждое сообщение состоит из:

  1. int указывает на длину данных.
  2. Двоичные данные, длина которых указана в 1.

Читая такое сообщение, я хотел бы что-то вроде:

int length = input.ReadInt();
byte[] data = input.ReadBytes(length);

Используя Socket.Receive или NetworkStream.Read, читается доступное количество байтов. Я хочу, чтобы вызов на ReadBytes блокировался до тех пор, пока не будет доступно length байт.

Есть ли простой способ сделать это без необходимости циклически повторять чтение, перезапускаясь со смещением в ожидании оставшихся данных?

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

Редактировать

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

Ответы [ 6 ]

5 голосов
/ 22 июля 2011

Что-то, где-то будет петля.В конце концов, может потребоваться многократное чтение сокетов.

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

0 голосов
/ 15 декабря 2011

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

        int numBytes = 0;
        int i = 0;
        while(numBytes != length)
        {
            numBytes += latestClient.Receive(body, numBytes, length-numBytes, SocketFlags.None);                
            if(i == 10000)
                throw new Exception("Could not read enough data.  read="+numBytes+" but expected="+length);
        }
0 голосов
/ 22 июля 2011

похоже, что оператор yield мог бы отлично подойти для этого сценария.

то есть, скажем, есть цикл, наблюдающий за поступающим потоком, и как только вы нажмете на каждое число длины, вы вернете контроль вызывающей стороне через 'yield' для IEnumerable / foreach.

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

0 голосов
/ 22 июля 2011

Взгляните на следующую ссылку: http://blog.stephencleary.com/2009/04/tcpip-net-sockets-faq.html

В этой ссылке вы найдете отличную информацию о сокетах, а также о библиотеке.

Единственное, что я хотел бы реализоватьявляется механизмом тайм-аута, чтобы избежать застревания, когда сеть выходит из строя.

0 голосов
/ 22 июля 2011

Вам нужно самостоятельно буферизовать данные, спецификация чтения такова, что при возврате они могут прочитать любое количество от 1 байта до размера буфера.

0 голосов
/ 22 июля 2011

Socket.Available сработает, если вы не возражаете против замкнутого цикла с ожиданием?

http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.available%28VS.71%29.aspx

...