Является ли хорошей идеей написать полное сообщение в NetworkStream или написать разделы каждого сообщения? - PullRequest
3 голосов
/ 05 февраля 2012

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

    NetworkStream ns = tcpClient.GetStream();

    byte[] message = Encoding.ASCII.GetBytes("This is a message.");
    ns.Write(message, 0, message.Length);

... было бы лучше, чем писать так ...

    NetworkStream ns = tcpClient.GetStream();

    byte[] message1 = Encoding.ASCII.GetBytes("This ");
    byte[] message2 = Encoding.ASCII.GetBytes("is ");
    byte[] message3 = Encoding.ASCII.GetBytes("a ");
    byte[] message4 = Encoding.ASCII.GetBytes("message.");

    ns.Write(message1, 0, message1.Length);
    ns.Write(message2, 0, message2.Length);
    ns.Write(message3, 0, message3.Length);
    ns.Write(message4, 0, message4.Length);

Есть ли многоразница в производительности программы или производительности сети для каждого метода?

Ответы [ 2 ]

4 голосов
/ 05 февраля 2012

Это сложно, и зависит от того, как настроен сокет. То, что вы пишете, не соответствует непосредственно полученному:

  • сетевой карте может потребоваться разбить ее на пакеты при передаче
  • сокет / NIC может быть настроен на объединение пакетов для передачи (сокращение фактических сетевых пакетов, но затрудняет уверенность в том, что вы отправили то, что, как вы думаете, у вас есть - возможно, оно буферизовано локально)

Обратите внимание, в частности, что NetworkStream.Flush() ничего не делает , поэтому вы не можете использовать это для проталкивания последних нескольких байтов

Хороший компромисс - обернуть NetworkStream в BufferedStream и настроить Socket с NoDelay = true (отключает локальную буферизацию вывода). BufferedStream позволяет вам продолжать запись в блоках любого размера (включая отдельные байты), не вызывая огромной фрагментации пакета; BufferedStream высветится, когда приблизится к заданному размеру. Однако, что важно, теперь у вас есть доступ к BufferedStream методу Flush(), который будет очищать буферизованные данные в сети; полезно, если у вас сложный задний разговор и вам нужно знать, что вы отправили конец вашего сообщения.

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

3 голосов
/ 05 февраля 2012

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

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

...