Эффект SO SNDBUF

Я не могу понять, как и почему работают следующие сегменты кода:

    /* Now lets try to set the send buffer size to 5000 bytes */
    size = 5000;
    err = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF,  &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, не имел никакого эффекта? Если да, то что именно? случилось? Какая-то фрагментация?

обновление: что произойдет, если сокет находится в неблокирующем режиме? Я попробовал следующее:

  1. изменение размера буфера до 10000 (5000*2) приводит к отправке 16384 байт
  2. изменение размера буфера до 20000 (10000*2) приводит к отправке 30000 байт

еще раз, почему?

2 ответов


задание SO_SNDBUF опция отличается для TCP и UDP.

  • для UDP это устанавливает ограничение на размер датаграммы, т. е. все, что крупнее, будет отброшен.
  • для TCP это просто устанавливает размер буфера в ядре для данного сокета (с некоторым округлением до границы страницы и с верхним пределом).

поскольку похоже, что вы говорите о TCP, эффект, который вы наблюдаете, объясняется сокетом находясь в блокирующем режиме, так что send(2) блокирует до тех пор, пока ядро не сможет принять все ваши данные и/или сетевой стек асинхронно де-очереди данных и толкая его на сетевую карту, тем самым освобождая пространство в буфере.

кроме того, TCP является потоковый протокол он не сохраняет никаких "сообщений" структуры. Один send(2) может соответствовать несколько recv(2)s на другой стороне, и наоборот. Рассматривайте его как byte-stream.


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