отправка небольших сегментов данных через TCP с winsock

Когда вам нужно отправить небольшие пакеты данных через TCP, дизайн вашего приложения winsock особенно важно. Дизайн, который не учитывает взаимодействие отложенные подтверждения, алгоритм nagle, и winsock буферизации может существенно сказаться на производительности. В данной статье рассматриваются эти вопросы, используя пару примеров, и получил ряд рекомендаций по отправке эффективно небольших пакетов данных из приложений winsock.
Более Подробную Информацию
Фон
Когда стек Microsoft TCP получает пакет данных, задержки 200 мс Таймер отключается. Когда подтверждение будет в конце концов отправили, задержка Таймер сбрасывается и начинает еще 200 мс задержки для следующего пакета данных. Для повышения эффективности в Интернет и Интранет-приложений, стек Microsoft TCP использует следующие критерии, чтобы решить, когда отправить одно подтверждение о полученных пакетах данных:

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

Чтобы избежать небольших пакетов данных перегружать сети, стек Microsoft TCP обеспечивает алгоритм nagle по умолчанию, который объединяет небольшой буфер данных из нескольких вызовов Send и задержки его отправки пока подтверждение для предыдущего пакета данных, полученных от удаленного узла. Следующие два исключения из алгоритма nagle.

Если стек совместно буфер данных превышает Максимальный размер пакета (mtu), полноразмерный пакет отправляется сразу же, не дожидаясь подтверждения от удаленного хоста. В сети Ethernet значение mtu для TCP/IP является 1460 байт.
Опции сокета tcp_nodelay применяется для отключить алгоритм nagle, небольшие пакеты данных передаются на удаленный хост без задержек.

Для оптимизации производительности на уровне приложений winsock копирует данные из буфера приложения отправлять вызовы буфер ядра winsock. Затем стек использует собственную эвристику (например, алгоритм nagle), чтобы определить, когда на самом деле положил пакет на проводе. Вы можете изменить размер буфера ядра winsock, выделенных на сокет, используя параметр so_sndbuf (это 8к по умолчанию). При необходимости, winsock может буфер значительно больше, чем размер буфера so_sndbuf. В большинстве случаев, завершение отправки в приложения только указывает на буфер данных в приложении, отправить вызов копируется в буфер ядра winsock и не указывает, что данные попали в сетевой среде. Единственное исключение-при отключении буферизации winsock, параметр so_sndbuf для 0.

Winsock использует следующие правила для обозначения завершения отправки заявки (в зависимости от того, как вызывается метод Send, уведомления о завершении может быть функция возврата из вызова блокировки, сигнализации события или вызов функции, уведомления, и т. д.):

Если сокет остается в пределах квоты so_sndbuf, winsock копирует данные из приложения отправки и указывает на завершение отправки заявки.
Если сокет находится за пределами квоты so_sndbuf и есть только один ранее буфер отправки в буфер стека ядра winsock копирует данные из приложения отправки и указывает на завершение отправки заявки.
Если сокет находится за пределами квоты so_sndbuf и есть больше, чем ранее в буфер и отправлять в буфер стека ядра winsock копирует данные из приложения отправки. Winsock не указывает на завершение отправки заявки до завершения стеке отправляет достаточно, чтобы поставить розетки в so_sndbuf квоты или только одно условие, ожидающих отправки.

Тематическое Исследование 1
Обзор:

Протокол TCP-клиент winsock нужно отправить 10000 записей на сервер TCP winsock для хранения в базе данных. Размер записи колеблется от 20 байт до 100 байт. Чтобы упростить логику приложения, конструкция выглядит следующим образом:

Клиент не только блокировки отправки. Сервер блокирующие полученного сообщения.
Клиент сокета so_sndbuf устанавливает в 0, так что каждая запись идет в один сегмент данных.
Сервер вызывает recv в цикле. Размещенные в recv буфера составляет 200 байт Для каждой записи могут быть получены за один вызов recv.

Производительность:
Во время тестирования, Разработчик обнаруживает, что клиент может отправить только пять записей в секунду на сервер. Общая 10000 записей максимум в 976 Кб данных (10000 * 100 / 1024), длится более получаса, чтобы отправить на сервер.

Анализ:
Поскольку клиент не установлен параметр tcp_nodelay, алгоритм nagle сил стека TCP ждать подтверждение, прежде чем он может отправить другого пакета по сети. Тем не менее, отключил клиента winsock буферизации, установив параметр so_sndbuf для 0. Поэтому, 10000 отправлять вызовы должны быть отправлены и ack'ED по отдельности. Каждый ACK является задержка 200 мс, поскольку происходит следующее TCP-стека сервера:

Когда сервер получает пакет, его 200 мс задержки Таймер отключается.
Сервер не нужно ничего отправлять обратно, так что подтверждение не может быть подключился бы.
Клиент не отправляет пакет, если предыдущий пакет признала.
Таймер задержки на сервере истекает и подтверждение направляется обратно.

Как улучшить:
Есть две проблемы с этой конструкцией. Во-первых, существует проблема задержки таймера. Клиент должен быть в состоянии, чтобы отправить два пакета на сервер в пределах 200 мс. Потому что клиент использует алгоритм nagle по умолчанию, его надо просто использовать по умолчанию буферизации winsock и не установлен параметр so_sndbuf для 0. После того, как стек TCP совместно буфер большего размера, чем Максимальный размер пакета (mtu), полноразмерный пакет отправляется сразу же, не дожидаясь подтверждения от удаленного хоста.

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

Пример 2
Обзор:
Клиентское приложение winsock TCP и открывает два соединения с winsock приложений TCP сервер предоставляет службы котировки акций. Первое соединение используется как командный канал для отправки символ акции к серверу. Второе соединение используется в качестве канала передачи данных для получения биржевых котировок. После двух соединений установлено, клиент отправляет символ акции к серверу через канал команды и ждет котировка вернется через канал данных. Он отправляет следующий запрос акции на сервер только после первой котировки акций не поступало. Клиент и сервер не установлен параметр so_sndbuf и tcp_nodelay.

Производительность:
Во время тестирования, Разработчик обнаруживает, что клиент может получить только пять цитат в секунду.

Анализ:
Такая конструкция позволяет только один запрос котировки акций одновременно. Первый символ акции отправляются на сервер через командную канала (соединения) и ответ сразу же отправили обратно от сервера к клиенту по каналу передачи данных (связи). Затем, клиент немедленно отправляет второй запрос акции и отправить немедленно возвращает буфер запрос отправки вызова копируется в буфер ядра winsock. Однако, стек TCP клиента не может послать запрос из буфера ядра сразу, потому что первые отправки по каналу передачи команд еще не признал. После Таймер задержки 200 мс на канал команды сервера истекает, ACK для первого символа запроса возвращается клиенту. Затем второй запрос был успешно отправлен на сервер после задержки на 200 мс. Цитата для второй символ акции приходит сразу обратно через канал передачи данных, поскольку в это время Таймер задержки на клиенте канал данных истек. Подтверждение за Предыдущий ответ цитата поступает на сервер. (Помните, что клиент не может отправить второй Запрос котировок на 200 мс, что дает время задержки таймер на клиенте, срок действия и отправить подтверждение на сервер.) В результате, клиент получает второй ответ цитата и может выдать еще один запрос, который подчиняется тем же цикла.

Как улучшить:
Два соединения (канала) дизайн-это лишнее. Если вы используете только одно подключение для запроса котировок и ответа ACK на запрос может быть прицепляться на на квоту ответ и немедленно возвращайся. Чтобы улучшить производительность, клиент может "мультиплекс" несколько запросов котировок на один вызов к серверу и сервер может также "мультиплекс" несколько ответов на предложение в один отправить вызов к клиенту. Если два однонаправленных канала конструкция действительно необходима для какой-либо причине, обе стороны должны установить параметр tcp_nodelay так, что мелкие пакеты могут быть отправлены немедленно, не дожидаясь подтверждение для предыдущего пакета.

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

  • Если данные сегменты не критическая, приложение должны сливаться в более крупный блок данных для передачи, чтобы отправить вызов. Поскольку буфера передачи, вероятно, будут скопированы в буфер ядра winsock, буфер не должен быть слишком большим. Немного меньше чем 8к обычно эффективен. Покуда ядра winsock получает блок превышает mtu, он будет посылать несколько пакетов полноразмерных и последний пакет, что еще осталось. Отправляющая сторона, за исключением последнего пакета, не будут бить по 200 мс задержки таймера. Последний пакет, если оно произойдет, будет нечетный пакет, все еще зависит от алгоритма отложенного подтверждения. Если отправка конца стека получает еще один блок больше, чем mtu, он по-прежнему сможете обойти алгоритм nagle.
  • Если возможно, избегайте подключений с однонаправленным потоком данных. Связь через сокеты однонаправленным, легко влияют nagle и задержка подтверждения алгоритмов. Если общение идет запрос и поток ответа, вы должны использовать один сокет не отправляет и recvs так что ACK может прицепляться на ответ.
  • Если всех мелких сегментов данных должны быть отправлены немедленно, установите параметр tcp_nodelay на передающем конце.
  • Если Вы не хотите, чтобы гарантировать, что пакет отправляется по сети после завершения отправки обозначается winsock, Вы не должны установить so_sndbuf нулю. В самом деле, 8k буфера по умолчанию был эвристически определил, чтобы хорошо работать для большинства ситуаций, и Вы не должны изменить его, если вы проверили, что ваш новый winsock буфера дает вам лучшую производительность, чем по умолчанию. Кроме того, параметр so_sndbuf к нулю в основном полезно для приложений, которые делают основную передачу данных. Даже тогда, для максимальной эффективности следует использовать его в сочетании с двойной буферизацией (более ожидающих отправки в любой момент времени) и перекрывающегося ввода/вывода.
  • Если доставка данных не гарантируется, используют udp.

Добавить комментарий

Обратная связь

Интересуют вопросы реализации алгоритмов, программирования, выбора электроники и прочая информация, постараюсь осветить в отдельных статьях

пишите мне на netdm@mail.ru