Что происходит, когда сервер tcp/udp публикуется быстрее, чем клиент потребляет?

Я пытаюсь понять, что происходит, когда сервер публикует (поверх tcp, udp и т.д.) быстрее, чем клиент может потреблять данные.

В рамках программы я понимаю, что если очередь находится между производителем и потребителем, она начнет увеличиваться. Если нет очереди, то производитель просто не сможет произвести ничего нового, пока потребитель не сможет потреблять (я знаю, что может быть много других вариантов).

Я не понимаю, что происходит, когда данные покидают сервер (который может быть другим процессом, машиной или центром обработки данных) и отправляется клиенту. Если клиент просто не может достаточно быстро реагировать на входящие данные, предполагая, что сервер и потребитель очень слабо связаны, что происходит с данными в полете?

Где я могу прочитать, чтобы получить подробную информацию по этой теме? Мне просто нужно прочитать данные низкого уровня TCP/UDP?

Спасибо

Ответы

Ответ 1

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

В UDP нет такой системы управления потоком; это ненадежно в конце концов. UDP-стеки как на клиенте, так и на сервере разрешают отбрасывать дейтаграммы, если они чувствуют себя так, как и все маршрутизаторы между ними. Если вы отправляете больше датаграмм, чем ссылка может доставить клиенту, или если ссылка поставляет больше датаграмм, чем может получить ваш код клиента, некоторые из них будут выброшены. Сервер и клиентский код, вероятно, никогда не узнают, если вы не создали какой-либо надежный протокол по базовому UDP. Хотя на самом деле вы можете обнаружить, что датаграммы НЕ выбрасываются сетевым стеком и что драйверы NIC просто пережевывают весь доступный неуправляемый пул и в конечном итоге приводят к сбою системы (см. этот блог для более подробной информации).

Назад с TCP, как ваш код сервера работает с окном TCP Window, будет зависеть от того, используете ли вы блокирующий ввод-вывод, неблокирующий ввод-вывод или асинхронный ввод-вывод.

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

  • Если сервер использует неблокирующий ввод-вывод, вы, скорее всего, получите сообщение об ошибке, сообщающее, что вызов заблокирован; вы можете делать другие вещи, но ваш сервер должен будет повторно отправить данные позже...

  • Если вы используете асинхронный ввод-вывод, все может быть сложнее. С асинхронным вводом-выводом с использованием портов ввода-вывода ввода-вывода в Windows, например, вы не заметите ничего другого. Ваши совпадающие посылы по-прежнему будут приниматься просто отлично, но вы можете заметить, что они занимают больше времени. Наложенные посылки помещаются в очередь на вашем сервере и используют память для ваших перекрывающихся буферов и, вероятно, используют "не выгружаемый пул". Если вы продолжаете выдавать перекрывающиеся отправки, тогда вы рискуете исчерпать память не выгружаемого пула или использовать потенциально неограниченный объем памяти в качестве буферов ввода-вывода. Поэтому при асинхронном вводе-выводе и серверах, которые МОГУТ генерировать данные быстрее, чем их клиенты могут их потреблять, вы должны написать свой собственный код управления потоком, который вы используете, используя пополнение от ваших записей. Я написал об этой проблеме в своем блоге здесь и здесь и моя серверная платформа предоставляет код, который автоматически обрабатывает его.

Что касается данных "в полете", то стеки TCP в обоих одноранговых узлах будут обеспечивать, чтобы данные поступали как ожидалось (то есть по порядку и без чего-либо отсутствующего), они будут делать это путем повторной отправки данных по мере необходимости.

Ответ 2

TCP имеет функцию управление потоком.

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

UDP, с другой стороны, совершенно другой. Сам UDP не делает ничего подобного и начнет отбрасывать данные, если он поступит быстрее, чем может обрабатывать процесс. Было бы до приложения добавлять логику к протоколу приложения, если она не может потерять данные (т.е. Если требуется "надежный" поток данных).

Ответ 3

Сервер не может быть быстрее клиента в течение длительного времени. После того, как клиент работает некоторое время, система, в которой он размещается, блокирует его при записи в сокете (запись может блокироваться на полном буфере, так же как чтение может блокироваться в пустом буфере).

Ответ 4

Если вы действительно хотите понять TCP, вам очень нужно прочитать реализацию в сочетании с RFC; реальные реализации TCP не соответствуют указанным. Например, у Linux есть концепция "давления памяти", которая защищает от исчерпания ядра (довольно небольшого) пула памяти DMA, а также предотвращает запуск одного сокета из любого другого из буфера.

Ответ 5

С TCP это невозможно.

В случае UDP пакеты будут потеряны.

Ответ 6

Статья в Wikipedia TCP показывает формат заголовка TCP, в котором хранятся размер окна и порядковый номер подтверждения. Остальные поля и описание должны дать хороший обзор того, как работает дросселирование передачи. RFC 793 определяет основные операции; страницы 41 и 42 подробно описывают управление потоком.