Python Recv() срыв

Я пишу очень простой HTTP-клиент:

import socket
from socket import *

Payload = """GET /test.html HTTP/1.1
Accept: */*
Accept-Language: en-us
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)
Accept-Encoding: gzip, deflate
Proxy-Connection: Keep-Alive
Host: example.com
Pragma: no-cache

"""

def SendAndReceive(Host, Payload):
    s = socket(AF_INET, SOCK_STREAM)
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    s.connect(Host)    
    s.sendall(Payload)
    tdata=[]
    while True:
        data = s.recv(1024)
        if not data: 
           break
        tdata.append(data)
    print ''.join(tdata)
    return ''.join(tdata)

SendAndReceive(("www.example.com",80),Payload)

По некоторым причинам recv() останавливается на некоторое время (~10 секунд), а затем возвращает данные. Я не уверен, что не так с моим кодом, любая помощь будет принята с благодарностью.

Спасибо!

2 ответа

Решение

Вы выполняете запрос HTTP/1.1, который неявно означает поддержание активности, например, сервер может поддерживать соединение открытым после выполнения запроса, чтобы получить больше запросов для того же соединения. В этом случае сервер через 10 секунд решает, что он не будет ждать больше запросов, другие серверы могут ждать дольше. Вы также не проверяете ответ сервера на кодирование по длине контента или по частям, а просто предполагаете, что сервер закроется после выполнения запроса. Это неправильно (поддерживать жизнь). Кроме того, у вас есть заголовок прокси-соединения, который ничего не делает, потому что это не запрос прокси (и сам заголовок прокси-соединения недопустим, для разговора с прокси требуется заголовок соединения).

Проще всего было бы выполнить запрос HTTP/1.0 и не указывать заголовок соединения или установить его как "закрыть". Затем сервер закроет соединение после ответа. Кроме того, вам не нужно иметь дело с чанкованным кодированием.

Как объяснил Штеффен, это связано с поддержанием жизни. Например, если вы протестируете его на google.com, вы будете ждать очень долго. Вы можете изменить свой код и увидеть время ожидания следующим образом:

# Payload remains the same
import socket as socket_module
from socket import *
def SendAndReceive(Host, Payload):
    s = socket(AF_INET, SOCK_STREAM)
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
    # or you could do s.setblocking(0) for timeout of 0 seconds
    s.settimeout(1)
    s.connect(Host)
    s.sendall(Payload)
    tdata=[]
    while True:
        try:
            data = s.recv(1024)
        except socket_module.error:
            # TIMEOUT
            break
        if not data:
            break
        tdata.append(data)
    print ''.join(tdata)
    return ''.join(tdata)

Таким образом, вы не получите ошибку.

Другие вопросы по тегам