Подтвердить что ты не робот

Что такое хороший размер буфера для программирования сокетов?

Мы используем .Net и сокеты. Сервер использует метод Socket.Sender(bytes []), поэтому он просто отправляет всю полезную нагрузку. С другой стороны мы клиенты, потребляющие данные. Socket.Receive(буфер []). Во всех примерах Microsoft (и других) они, похоже, придерживаются размера буфера 8192. Мы использовали этот размер, но время от времени мы отправляем данные до клиентов, которые превышают этот размер буфера.

Есть ли способ определить, сколько данных отправил нам метод отправки сервера? Каков наилучший размер буфера?

4b9b3361

Ответ 1

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

Вы не можете определить, сколько данных сервер отправил - это поток данных, и вы просто читаете куски за раз. Вы можете прочитать часть того, что сервер отправил в одном вызове "Отправить", или вы можете прочитать данные из двух вызовов "Отправка" в одном вызове "Получить". 8K - это разумный размер буфера - не такой большой, что вы будете тратить много памяти, и не настолько мал, что вам придется использовать нагрузку впустую. 4K или 16K, вполне возможно, тоже в порядке... Я лично не стал бы переходить выше 16K для сетевых буферов - я подозреваю, что вы редко заполняете их.

Вы можете поэкспериментировать, пытаясь использовать очень большой буфер и регистрировать, сколько байтов было получено в каждом вызове - это даст вам некоторое представление о том, сколько вообще доступно, но на самом деле это не показало бы эффекта использования меньший буфер. Что вы имеете, используя буфер 8K? Если это производительность, есть ли у вас какие-либо доказательства того, что этот аспект вашего кода является узким местом производительности?

Ответ 2

Это зависит от вашего протокола. Если вы ожидаете, что сообщения превышают 8192 байта, вам следует соответственно увеличить размер вашего буфера. Но имейте в виду, что этот размер буфера предназначен только для одного вызова Receive. Если вам действительно нужно/нужно, вы можете циклически перебирать Receive несколько раз и копировать полученные данные в произвольно большую структуру данных или буфер.

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

Ответ 3

Ответ Джона Скита, к сожалению, оставляет большую часть изображения - размер буфера отправки и продукт задержки полосы пропускания в трубе вы пишете.

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

Рассмотрим соединение, которое имеет скорость 1 гигабит, и имеет одностороннюю задержку в 10 миллисекунд, в среднем. Время прохождения в оба конца (например, количество времени, которое проходит между вашим сокетом, отправляющим пакет, и временем, которое он получает для этого пакета и, таким образом, знает, что посылает больше данных) обычно удваивает задержку.

Итак, если у вас 1 гигабитное соединение и RTT 20 миллисекунд, то этот канал имеет 1 гигабит/с * 20 миллисекунд == 2,5 мегабайта данных в полете во все времена, если он полностью используется.

Если ваш буфер TCP-отправки составляет менее 2,5 мегабайт, то один сокет никогда не будет полностью использовать этот канал - вы никогда не получите гигабит/сек производительности из своего сокета.

Если ваше приложение использует множество сокетов, то общий размер всех буферов TCP-отправки должен быть 2,5 МБ, чтобы полностью использовать этот гипотетический 1-гигабитный/20 мс RTT-канал. Например, если вы используете 8192-байтовые буферы, для заполнения этого канала вам потребуется 306 одновременных сокетов TCP.

Ответ 4

8192 было бы идеальным. Если у вас есть данные, превышающие этот размер, лучше было бы отправлять данные в пакеты с постоянной длиной.

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