Networkstream.Write () Проблема блокировки - PullRequest
6 голосов
/ 24 августа 2011

Я сейчас тестирую управляемую сетевую библиотеку c #, которую написал, и столкнулся со случайной проблемой.Эта проблема проявляется в очень согласованном (всегда в пределах 30 мс) блоке 5000 мс в networkstream.write () для, возможно, 1% всех операций отправки.Это тестовая среда, все работают локально, каждый раз используя один и тот же размер пакета (2 МБ).На стороне клиента я непрерывно записываю следующее в подключенный сетевой поток:

tcpClientNetworkStream.Write(headerBytes, 0, headerBytes.Length);
tcpClientNetworkStream.Write(dataBytes, 0, dataBytes.Length);

, а на стороне сервера я использую асинхронное чтение в ожидании данных.Как только данные появляются, я использую цикл while над tcpClientNetworkStream.DataAvailable, пока все данные не будут получены.

Мне известно, что networkstream.write () может блокироваться, если буферы заполнены, но если это проблема, я не могу придумать более быстрый способ их очистки на стороне сервера (размеры буфера отправки и получения)по умолчанию на 8192 байта).Тот факт, что блок настолько последовательный, кажется очень странным.Моей первой мыслью была, возможно, какая-то форма Thread.Sleep, но полный поиск по проекту ничего не показал.Если бы кто-то мог помочь пролить свет на эту проблему, это было бы очень полезно.

Marc

отредактировать, чтобы добавить: Хак, который, кажется, устраняет проблему, заключается в следующем (хотя естьсвязанное снижение производительности из-за BlockCopy):

byte[] bytesToSend = new byte[headerBytes.Length + dataBytes.Length];
Buffer.BlockCopy(headerBytes, 0, bytesToSend, 0, headerBytes.Length);
Buffer.BlockCopy(dataBytes, 0, bytesToSend, headerBytes.Length, dataBytes.Length);
tcpClientNetworkStream.Write(bytesToSend, 0, bytesToSend.Length);

edit to add2: я также воспроизвел проблему, используя две асинхронные записи с сигналом потока между ними.На данный момент единственное решение, которое у меня есть, это одиночная операция записи, как в приведенном выше редактировании.

редактирование в add3: Хорошо, следует еще одно возможное исправление.Мне все еще интересно знать, почему последовательная запись иногда «блокирует» так, как она это делает.

BufferedStream sendStream = new BufferedStream(tcpClientNetworkStream);
sendStream.Write(bytesToSend, 0, bytesToSend.Length);
sendStream.Write(packet.PacketData, 0, packet.PacketData.Length);
sendStream.Flush();

edit to add4: После дальнейшего обширного тестирования решение «edit to add3» не делаетпроблема исчезнет, ​​это только уменьшает количество случаев отправки примерно до 0,1%.Гораздо лучше, но далеко не решено.Я заменим асинхронное чтение на блокирующее чтение, чтобы посмотреть, сортирует ли оно это, как это было предложено PaulF.

1 Ответ

2 голосов
/ 16 сентября 2011

Хорошо, конкретных ответов на этот вопрос нет, поэтому я сделаю все возможное, чтобы сделать небольшой вывод сам. Мое лучшее предположение состоит в том, что эта проблема изначально была вызвана тем, что я заполнял буфер tcp быстрее, чем очищал его. Если буфер заполнен, существует некоторое неизвестное время ожидания перед попыткой добавить дополнительные данные. Эта проблема, возможно, будет наиболее очевидной при отправке и получении данных на одном компьютере. Важно помнить, что размер буфера чтения по умолчанию в .net составляет всего 8192 байта, поэтому, если запись выполняется в гораздо больших блоках, возможно, стоит рассмотреть возможность увеличения этого размера буфера чтения до чего-то большего, например 512000 байт. Однако это само по себе вызывает другие проблемы из-за большой кучи объектов и т. Д., Но это потенциально обсуждение другого вопроса.

...