Как избежать слияния http пакетов? - PullRequest
0 голосов
/ 15 марта 2020

Я пишу go коды для отправки потоковых блоков Http:

func handle02(w http.ResponseWriter, req *http.Request){
    for {
        n, err := w.Write([]byte("h\r\n"))
        if ww,ok := w.(http.Flusher); ok {
             ww.Flush()
        }
        time.Sleep(time.Millisecond * 10)
        if err != nil {
            fmt.Println(err, n)
            break
        }
    }
}

Клиент получает блоки и печатает их

import requests

a = requests.post(url, stream=True)
for line in a.iter_lines():
    if line:
        print(line)

Он отлично работает на win10 и Linux , Но когда я запускаю клиент на сервере Windows, он объединяет куски в один пакет. Я использую wireshark, чтобы проверить и найти, что он упакует куски в большой пакет.

enter image description here

Но на win10 результат wireshark равен enter image description here

Каждый грипп sh вируса будет производить небольшой пакет на клиенте. Все в порядке. Я пробовал много методов из inte rnet, таких как «отключить автонастройку tcp», «отключить алгоритм Nagle»

, но они не работают. Так как я мог запретить объединение пакетов?

Спасибо

1 Ответ

3 голосов
/ 15 марта 2020

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

Несмотря на то, что в некоторых конкретных случаях c может оказаться возможным добиться более детального контроля, эту гранулярность трудно поддерживать, когда задействованы разные ОС, разные версии библиотек, прокси и т. Д. c - потому что они заботятся только о степени детализации, которая требуется от стандарта, а не о той, которую вы хотите достичь путем неправильного использования протокола HTTP .

Если вы хотите иметь более тонкую гранулярность, у вас есть использовать протокол так, как он был разработан , а не так, как он работает для вас в некоторых конкретных c случаях. Это означает, что вам нужно использовать несколько запросов для получения нескольких ответов, вместо того, чтобы ожидать нескольких ответов для одного запроса. Или используйте WebSockets, которые допускают произвольные сообщения в любом направлении в произвольные моменты времени. Или используйте TCP напрямую, что тоже позволяет.

РЕДАКТИРОВАТЬ: На основе комментариев клиент работает за брандмауэром, а сервер снаружи. Маловероятно, что проблема вызвана Windows против Linux, но более вероятно, что это вызвано брандмауэром. Брандмауэр, вероятно, использует (прозрачный) прокси , и, таким образом, OP сталкивается с проблемой , описанной в документации для Flusher :

... если клиент подключен через HTTP-прокси, буферизованные данные могут не достичь клиента до тех пор, пока ответ не завершится

Это также видно из перехвата пакетов: в успешном случае один можно увидеть использование фрагментирования HTTP, то есть 33 0d 0a 68 0d 0a 0d 0a на скриншоте - это отдельный фрагмент HTTP:

3\r\n     <<< this is the length of the chunk in hex
h\r\n     <<< this is the payload of the chunk
\r\n      <<< end of chunk

В отличие от этого при захвате пакета в нерабочем случае можно увидеть, что разбиение не выполняется т. е. 68 0d 0a 68 0d 0a 68 0d 0a ...:

h\r\n 
h\r\n
h\r\n
...

Это означает, что (прозрачный) прокси-сервер, скорее всего, читает чанкованный ответ и передает его как чанкованный. Такое поведение не является чем-то необычным, особенно если прокси-серверы выполняют анализ контента, как это часто происходит в брандмауэрах. Но может также случиться так, что прокси-сервер изменяет запрос клиента на HTTP / 1.0, и в этом случае сервер в первую очередь не будет использовать фрагментированное кодирование HTTP, поскольку это поддерживается только в HTTP / 1.1.

...