Каков путь повторной сборки ответа HTTP?

361
cg14

Я пытаюсь понять, как операционные системы обычно осуществляют повторную сборку сетевых запросов. Из моего лучшего понимания верно следующее:

HTTP-запрос делается на прикладном уровне с использованием некоторой библиотеки HTTP. Эта HTTP-библиотека действительно является оболочкой для некоторой реализации сокетов ОС.

«Передающий» сокет создается с использованием назначения и источника HTTP-запроса.

«Принимающий» сокет создается с использованием IP-адреса устройства и рандомизированного (свободного) порта.

HTTP-сообщение «отправляется» с использованием «передающего» файлового дескриптора сокета.

Метод «send» сокета отправляет сообщение реализации TCP операционной системы.

Реализация TCP сегментирует сообщение HTTP, добавляя порт назначения (предоставленный при создании экземпляра сокета) и порт источника. (Я предполагаю, что это каким-то образом передается в зависимости от реализации.) Как только HTTP-сообщение было сегментировано и к нему добавлены заголовки TCP, сегменты TCP затем передаются в реализацию IP ОС.

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

Затем IP-пакеты упаковываются в заголовки Ethernet, отправляются на маршрутизатор, отправляются на сервер, сервер обрабатывает запрос и отправляет ответ.

Здесь мое понимание нарушается в отношении того, что именно происходит в процессе сборки.

Как ответ возвращается в приемный буфер «принимающего» сокета, чаще после того, как IP-пакет возвращается на устройство?

Очевидно, что заголовки сбрасываются, но какие шаги предпринимаются, чтобы вернуть его конкретно в приемный буфер «принимающего» сокета, а затем из сокета обратно в приложение?

PS Я надеюсь на более подробную техническую реализацию, чем просто «IP повторно собирает его» или «TCP повторно собирает его» и передает его на следующий уровень. Я надеюсь понять, как именно это происходит, а не только теоретически (хотя я понимаю, что это зависит от ОС).

Редактировать:

Чтобы внести ясность в предмет, я хотел бы отметить мои ссылки на сокет и любой метод сокета, относящийся к ОС Linux.

0
Комментарии не для расширенного обсуждения; этот разговор был [перемещен в чат] (https://chat.stackexchange.com/rooms/79429/discussion-on-question-by-cg14-what-is-the-reassembly-path-of-a-http- ответ). Journeyman Geek 5 лет назад 0

2 ответа на вопрос

1
cg14

Хорошая находка от Mike Penningtion (в комментариях ), где можно найти подробное техническое описание пути запроса по сетевому стеку и резервному копированию (специфично для ОС Linux 2005).

Более подробный обзор, из которого были извлечены следующие шаги :

Обратите внимание, что хотя перечисленные шаги не так подробны, как в документе, упомянутом выше, примерно эти шаги:

ОС имеет выделенный файловый дескриптор для порта Ethernet Ethernet,

The rx ring is a ring in the kernel memory where the network card transfers the incoming packet through DMA. The raw data which is stored in the rx ring structure is either copied into a sk buff structure. 

Затем запускается ISR для перемещения пакета на сетевой уровень. Обратите внимание, что здесь выбирается, обрабатывать ли пакет или пересылать его (что было интересно, так как я думаю, возможно, именно так работает включение пересылки, например, для VPN)

Если он действителен, он переходит на IP-уровень. Он проверяет свой протокол (из заголовка IP) и, если протокол TCP, вызывает tcp v4 rcvфункцию, тем самым переходя на уровень TCP.

И эта часть имеет решающее значение:

The next step for this function is to find an open socket for this incoming packet, 

это делается путем вызова tcp v4 lookup, в следующем сегменте кода:

sk = __tcp_v4_lookup(skb->nh.iph->saddr, th->source, skb->nh.iph->daddr, ntohs(th->dest), tcp_v4_iif(skb)); 

По сути, я понял, что существует LUT, сопоставляющий сокет TCP с адресом / портом источника и получателя соединения сокета, как указано в этом вызове функции.

Если существует допустимый сокет, данные помещаются в tcp_data_queueстек для использования приложения.

0
Mike Pennington

(из комментариев )

Я получаю инкапсуляцию. Допустим, в ОС есть выделенный дескриптор файла, открытый на выделенном порту Rx Ethernet. Он удаляет заголовок Ethernet из фрейма и передает его в некоторую функцию анализа IP, чтобы удалить целевой IP. Он помещает это в некоторую структуру, а затем отправляет ее и структуру на уровень TCP. Здесь он удаляет его из порта назначения и помещает его в ту же структуру. Здесь должно быть некоторое сопоставление с дескриптором файла сокетов на основе порта и ip, чтобы поместить данные в буфер, назначенный дескриптору файла. Это мой лучший способ пойти на это. Но я хотел бы знать, что на самом деле происходит.

Довольно старая версия того, что вы ищете, находится здесь: сетевой стек Linux . Я пытаюсь найти что-то более новое, чем описание 2005 года, потому что некоторые изменения в Linux изменились с тех пор. Большая часть информации о буферизации сокетов хранится в структуре, называемой an sk_buff, которая представляет собой структуру linux, которая содержит указатели на дескриптор сокета TCP, а также все буферы чтения / записи сокетов.

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