2009-09-01 4 views
9

Как работает чтение (буфер, смещение, длина), если я передаю длину для чтения как 32, означает ли это, что он будет блокировать до получения 32 байтов?C# Networkstream.read()

Я понимаю, что он вернет и исключение или 0 в случае исключения сокета или если соединение будет закрыто, соответственно.

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

Важны и то еще не ответил

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

+0

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

+0

Как отвечать на вторую часть вопроса, если я отправляю 32 байта, и я определяю длину 32 байта в методе чтения, гарантирует ли это, что он обязательно прочитает 32 байта? я имею в виду, что он будет заблокирован, пока не будет получено 32 байта. – Kazoom

+0

@Kazoom, по-моему, на этот вопрос уже были заданы два разных поста и ссылки на них. Он будет блокироваться, пока не будет получен хотя бы один байт. – scottm

ответ

6

Нет, он не будет блокироваться. Операция чтения считывает как можно больше данных, вплоть до количества байтов, заданных параметром размера. http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read.aspx

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


UPDATE: я был неправ, когда я сказал «Там нет блокировки вообще Если данные не доступны для чтения, метод Read возвращает 0», но я был прав, когда я сказал, что это Wouldn» t, ожидая, чтобы заполнить весь буфер, который он сценарий описан в вопросе Kazoom.

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

Создание утешать проектов

На одном конце, у вас есть слушателя:


IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); 
TcpListener listener = new TcpListener(ep); 
listener.Start(); 
TcpClient client = listener.AcceptTcpClient(); 
NetworkStream s = client.GetStream(); 
byte[] buffer = new byte[32]; 
Console.WriteLine(s.Read(buffer, 0, 32)); 
Console.WriteLine("Press any key to continue..."); 
Console.Read(); 

На другом конце, мы посылаем только один байт:


IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); 
TcpClient client = new TcpClient(); 
client.Connect(ep); 
client.GetStream().Write(new byte[] { 60 }, 0, 1); 
Console.WriteLine("Press any key to continue..."); 
Console.Read(); 

Обе стороны будут работать пока они не достигнут Console.Read(). Обратите внимание, что слушатель не блокирует чтение.

Слушатель будет печатать «1»

+0

, так что он блокируется на уровне байта, а не на уровне бит – Kazoom

+0

Там вообще нет блокировки. Если для чтения нет данных, метод Read возвращает 0. –

+0

Что мы понимаем под отсутствием данных, что если отправитель отправляет 32 байта, это гарантирует, что чтение вернется только после чтения этих 32 байтов (учитывая, что это tcp) – Kazoom

2

Он будет блокировать до тех пор, пока не получит 32 байта, или соединение закрывается. Асинхронные методы BeginRead() и EndRead() должны использоваться для обеспечения неблокирующих чтений.

Вот пример кода, наглядно демонстрирующего эффект блокировки.

Socket one = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
    Socket two = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

    IPEndPoint ep = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345); 

    one.Bind(ep); 
    one.Listen(1); 
    two.Connect("127.0.0.1", 12345); 
    one = one.Accept(); 

    NetworkStream s = new NetworkStream(two); 
    byte[] buffer = new byte[32]; 
    s.Read(buffer, 0, 32); 

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

Даже если этот код создает эффект блокировки, это только из-за реализации NetworkStream о Stream's abstract Read() method (который должен быть переопределен). В документации по Stream.Read() указано следующее:

Реализации возвращают количество прочитанных байтов . Возвращаемое значение равно нулю , только если позиция в данный момент находится на конца потока.

Именно поэтому код блокируется, когда получены данные NO, и конец потока не был достигнут. Он также продолжает говорить:

Реализация будет блокировать до по меньшей мере, один байт данных не может быть чтения, в том случае, если данные не доступны . Чтение возвращает 0 только тогда, когда данных больше нет в потоке и больше не ожидается (например, закрытый разъем или конец файла ). Реализация может возвращать меньше байт, чем запрашивалось, даже если конец потока не был достигнут.

+0

http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read(VS.71).aspx – Kazoom

+0

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

+0

@Kazoom. Если вы прочитали 20 байтов и соединение было закрыто, возвращаемый номер равен 20. – scottm

1

Вопрос о тайм-ауте, по-видимому, остается без ответа.

Ответ заключается в том, что вы можете установить stream.ReadTimeout и stream.WriteTimeout, где stream - ваш объект NetworkStream. Это обрабатывает блокирующий случай без ответа вообще. Без установки этих значений поток будет ждать бесконечно.

Смежные вопросы