Сколько мне ждать, пока буфер отправки сокета не станет пустым в С++?

Я пытаюсь ограничить свою сеть только одним приемником.

Во-первых, я определяю размер SO_SNDBUF по:

getsockopt(sendsockfd, SOL_SOCKET, SO_SNDBUF, &sndBufferSize, &sbsLen);

Затем я продолжаю заполнять этот буфер, пока он не будет полностью заполнен:

if (sndBufferSize - NbBytesInBuffer >= HEADER){
    memcpy (sendBuffer + NbBytesInBuffer, &buf_header, HEADER);
    NbBytesInBuffer +=HEADER;
}

Конечно, я упоминаю только соответствующую часть моего кода.

Наконец, когда буфер заполнен, напишите в сокет.

if (sndBufferSize - NbBytesInBuffer < HEADER)
sentSize = write(sendsockfd,sendBuffer,NbBytesInBuffer);
...

Моя проблема еще не упоминается. Все вышеперечисленное работает отлично, пока я не хочу снова отправить данные.

Теперь, поскольку я хочу отправить максимально возможную скорость, я должен ждать как можно меньше. (т.е. я должен отправить повторно, буфер отправки пуст).

Как определить необходимое время для write(), чтобы повторно очистить буфер отправки (наиболее оптимальным образом)?

P.S. Пожалуйста, не говорите мне ждать произвольное время (например, usleep(10000);)


person Mohamad-Jaafar NEHME    schedule 28.12.2014    source источник
comment
Вы рассматривали select ?   -  person Jarod42    schedule 28.12.2014
comment
У меня только один ресивер. я отредактировал свой вопрос   -  person Mohamad-Jaafar NEHME    schedule 28.12.2014
comment
select также работает с одним fd, может сказать, можете ли вы читать или писать в определенный fd и имеет тайм-аут.   -  person Jarod42    schedule 28.12.2014
comment
Это очень похоже на чрезмерную инженерию.   -  person Lightness Races in Orbit    schedule 28.12.2014
comment
@ Jarod42, действительно, это не решит проблему, потому что что, если select вернет «еще недоступно». Итак, я должен использовать цикл. А затем подождите в цикле.   -  person Mohamad-Jaafar NEHME    schedule 28.12.2014


Ответы (1)


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

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

person Mike DeSimone    schedule 28.12.2014
comment
Ты прав. Вот о чем я думаю. Просто позвольте мне проверить это. - person Mohamad-Jaafar NEHME; 28.12.2014
comment
Я не знаю, что происходит. Но я пробовал это раньше и столкнулся с некоторыми проблемами с памятью :) В любом случае, большое спасибо. - person Mohamad-Jaafar NEHME; 28.12.2014
comment
Что ж, если у вас действительно оптимистичная ОС с огромными буферами или какими-то подобными странностями, вы можете попасть в ситуацию, когда вам может не хватить памяти, создавая гигантский буфер отправки. Одно из упражнений, которое можно попробовать, — это определить, сколько времени потребуется для передачи фиксированного объема данных с различными размерами блоков (например, передача 10 МБ блоками по 4 КБ, 8 КБ, 16 КБ, ... 1024 КБ). Наступает момент, когда большие буферы уже не помогают. - person Mike DeSimone; 28.12.2014
comment
Спасибо. Это был бы мой следующий вопрос :) - person Mohamad-Jaafar NEHME; 28.12.2014
comment
Кстати, есть ли смысл фиксировать размер сообщения и увеличивать/уменьшать размер окна/пакета? Другими словами, влияет ли это на пропускную способность? Тривиальный ответ - да. Итак, в чем разница? - person Mohamad-Jaafar NEHME; 28.12.2014
comment
Если вы используете TCP/IP, сетевой стек должен позаботиться об оптимизации необходимых параметров. В этом случае любой размер write будет разбит (фрагментирован) на IP-пакеты размером до MTU, который обычно составляет 1500 или 9000 байт. Стек попытается оптимизировать пропускную способность, регулируя количество таких пакетов, которые он будет передавать, прежде чем ожидать подтверждения для любого из них. Избавление от размеров окон, вероятно, испортит эти настройки, если что. - person Mike DeSimone; 28.12.2014