Каково предсказуемое поведение изменения SOL_SOCKET, SO_RCVBUF на лету в сокете UDP?

Что должно произойти, если мы изменим размер входного буфера сокета сервера UDP на лету в системе Linux?

setsockopt(sock, SOL_SOCKET, SO_RCVBUF, ...)

Меня особенно интересуют эти вопросы:

  • Если я уменьшусь ниже того, что в настоящее время находится в буфере, это просто отбросит самые старые/самые новые? дейтаграммы правильно, или он может сбросить все, что там есть, или, что еще хуже, может повредить данные, например, обрезать дейтаграмму?
  • Будет ли сокращение буфера даже экономить память, или что-то мешает системе повторно использовать эту память?
  • Является ли поведение предсказуемым или иногда оно может вести себя случайным образом?

person FlorianB    schedule 25.10.2020    source источник


Ответы (1)


Прежде всего: термин «буфер» может сбивать с толку: ядро ​​на самом деле сохраняет пакеты не в буферах фиксированного размера, а в очередях, называемых бэклогами (см. include/net/sock.h:400). Размер, установленный с помощью SO_RCVBUF и SO_SNDBUF, ограничивает только максимальный размер невыполненной работы.

Если я уменьшусь ниже того, что в настоящее время находится в буфере, это просто отбросит самые старые/самые новые?

Нет, то, что уже было получено, сохраняется. Дейтаграммы не выбрасываются. Единственное, что происходит, когда вы делаете setsockopt(SO_RECVBUF), это то, что изменено значение поля sk_rcvbuf сокета. Никакие другие действия не выполняются.

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

Будет ли сокращение буфера даже экономить память, или что-то мешает системе повторно использовать эту память?

Как я уже говорил ранее, поскольку буфер на самом деле не является буфером и не имеет фиксированного размера, изменение SO_RECVBUF ничего не изменит сразу.

Есть два сценария:

  1. Если размер невыполненной работы был ниже (или равен) указанному размеру: новый максимальный размер будет ограничен, поэтому он сэкономит память в будущем за счет потенциального потеря пакетов.
  2. Если размер невыполненной работы был выше указанного размера: память в конечном итоге будет освобождена, когда пользовательское пространство получит буферизованные пакеты, и она не будет снова увеличиваться сверх установленного значения. Это снова сэкономит память в будущем.

Является ли поведение предсказуемым или иногда оно может вести себя случайным образом?

Глядя на код ядра, я бы сказал, что он на 100% предсказуем, как я описал выше. Однако я не совсем уверен, где это может быть задокументировано. Я бы сказал, что это интуитивно понятно, если вы думаете о буферах отправки и получения как об очередях (какими они на самом деле и являются).

person Marco Bonelli    schedule 25.10.2020