#c #linux #sockets #setsockopt
#c #linux #сокеты #setsockopt
Вопрос:
Я не могу понять, как и почему работают следующие сегменты кода :
/* Now lets try to set the send buffer size to 5000 bytes */
size = 5000;
err = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, amp;size, sizeof(int));
if (err != 0) {
printf("Unable to set send buffer size, continuing with default sizen");
}
Если мы проверим значение буфера отправки, оно действительно правильно установлено в 5000 * 2 = 10000.
Однако, если мы попытаемся отправить больше, чем размер буфера отправки, он отправит все это. Например:
n = send(sockfd, buf, 30000, 0);
/* Lets check how much us actually sent */
printf("No. of bytes sent is %dn", n);
Выводится значение 30000.
Как именно это сработало? Не повлиял ли тот факт, что размер буфера отправки был ограничен 10000? Если это произошло, что именно произошло? Какая-то фрагментация?
ОБНОВЛЕНИЕ: Что произойдет, если сокет находится в неблокирующем режиме? Я попробовал следующее:
- Изменение размера буфера на 10000 (5000 * 2) приводит к отправке 16384 байт
- Изменение размера буфера на 20000 (10000 * 2) приводит к отправке 30000 байт
Еще раз, почему?
Ответ №1:
Эффект от установки SO_SNDBUF
параметра отличается для TCP и UDP.
- Для UDP это устанавливает ограничение на размер дейтаграммы, т.е. все, что больше, будет отброшено.
- Для TCP это просто устанавливает размер буфера в ядре для данного сокета (с некоторым округлением до границы страницы и с верхним пределом).
Поскольку похоже, что вы говорите о TCP, эффект, который вы наблюдаете, объясняется тем, что сокет находится в режиме блокировки, поэтому send(2)
блокируется до тех пор, пока ядро не сможет принять все ваши данные, и / или сетевой стек асинхронно выводит данные из очереди и отправляет их на сетевую карту, освобождая таким образом место в буфере.
Кроме того, TCP является потоковым протоколом, он не сохраняет никакой структуры «сообщения». Один send(2)
может соответствовать нескольким recv(2)
s на другой стороне, и наоборот. Обрабатывайте это как поток байтов.
Комментарии:
1. и что произойдет, если сокет находится в неблокирующем режиме? Я попробовал следующее: 1) Изменение размера буфера на 10000 приводит к отправке 16384 байт 2) Изменение размера буфера на 20000 приводит к повторной отправке 30000 байт, почему?
2. @Arun: это просто округление.. почему это вообще имеет значение? вы не должны полагаться на тот факт, что буфер состоит из ровно n байт. ядро может выделить больше.
3. Во-первых, ядро не принимает размер вашего буфера как есть, как указывает @yi_H. Тогда сетевой стек работает асинхронно по отношению к вашему процессу. Попробуйте следующее — начните запись в сокет, но не читайте в другом размере . В конечном итоге вы получите короткое сообщение (ядро принимает меньше байтов, чем вы ему даете) или сбой записи.
4. Ну, у меня ничего не происходит в TCP-сокете. Я создал клиент-серверное приложение, в котором сервер после принятия соединения переходит в режим ожидания на неопределенное время, а клиент продолжает отправлять сообщения. Буфер никогда не переполняется, ни мой вызов отправки не блокируется, как сказано linux.die.net/man/2/send
Ответ №2:
SO_SNDBUF
настраивает буфер, который реализация сокета использует внутри. Если ваш сокет неблокирующий, вы можете отправлять только до настроенного размера, если ваш сокет блокирующий, ограничений для вашего вызова нет.