2014-01-24 5 views
0

Я пишу очень простой клиент HTTP:Python Recv() глохнет

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 сек), затем возвращает данные. Я не уверен, что не так с моим кодом, любая помощь будет принята с благодарностью.

Спасибо!

+0

Это происходит со всеми HTTP-серверами или с любым конкретным сервером? –

+0

Со всеми HTTP-серверами. В этом коде должно быть что-то не так. – n00bz0r

ответ

2

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

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

+0

Изменение HTTP/1.1 на HTTP/1.0 и продолжение работы для решения проблемы. Быстрый вопрос, как мне выполнить фактическую буферизацию recv()? Предположим, что этот сокет делает GET для изображения. – n00bz0r

+1

@ n00bz0r: хороший вопрос, паршивый комментарий, задайте новый вопрос! – SingleNegationElimination

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) 

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