Как отключить HTTP POST с истекшим временем ожидания с помощью urlopen by urllib2 в Python?

Обзор

Я использую urlopen из пакета Python 2.7.1 urllib2 для выполнения HTTP POST с машины Windows XP на удаленный веб-сервер Apache (, например встроенный -в веб-сервере. совместное использование Mac OS X ). Отправленные данные содержат некоторый идентификатор, данные и контрольную сумму, если все данные отправлены, сервер отвечает подтверждением. Контрольную сумму в данных можно использовать, чтобы проверить, все ли прибыло в порядке.

Проблема

Обычно это работает отлично, однако иногда подключение к Интернету плохое, часто потому, что клиент, отправляющий данные, использует соединение Wi-Fi или 3G. Это приводит к потере интернет-соединения на некоторое произвольное время. urlopen содержит параметр тайм-аута, чтобы убедиться, что это не заблокирует вашу программу и она сможет продолжить работу.

Это то, что я хочу, но проблема в том, что urlopen не останавливает сокет от продолжения отправки любых данных, которые он еще должен был отправить, когда наступил тайм-аут. Я протестировал это (с помощью кода, который я покажу ниже ), пытаясь отправить большой бит данных на свой ноутбук, я бы увидел сетевую активность на обоих индикаторах активности, затем я бы остановил беспроводную связь на ноутбук, подождите, пока функция не истечет, а затем повторно активируйте беспроводную связь, после чего передача данных продолжится, но программа больше не будет ожидать ответов. Я даже пытался выйти из интерпретатора Python, но он все равно отправлял данные, так что контроль над этим каким-то образом передается Windows.

Причины

Тайм-аут (как я понял )работает так :Он проверяет «время простоя»
. ([Python -Dev] Добавление тайм-аута сокета в urllib2)
Если вы установите тайм-аут на 3, он откроет соединение, запустит счетчик, затем попытается отправить данные и дождется ответа, если в какой-то момент до получения ответа таймер истекает, вызывается исключение тайм-аута. Обратите внимание, что отправка данных не считается «активностью» в отношении таймера тайм-аута.
(urllib2 истекает, но не закрывает соединение сокета #39;)
(Закрывает соединение urllib2)

По-видимому, где-то указано, что когда сокет закрывается/разыменовывается/собирается мусор, он вызывает свою функцию 'close', которая ожидает отправки всех данных перед закрытием сокета. Однако есть также функция выключения, которая должна немедленно остановить сокет, предотвращая дальнейшую отправку данных.
(socket.shutdown vs socket.close)
(http://docs.python.org/library/socket.html#socket.socket.close)

Чего я хочу

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

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

from urllib import urlencode
from urllib2 import urlopen, HTTPError, URLError
import socket
import sys

class Uploader:
    def __init__(self):
        self.URL = "http://.../"
        self.data = urlencode({'fakerange':range(0,2000000,1)})
        print "Data Generated"

    def upload(self):
        try:
            f = urlopen(self.URL, self.data, timeout=10)
            returncode = f.read()
        except (URLError, HTTPError), msg:
            returncode = str(msg)
        except socket.error:
            returncode = "Socket Timeout!"
        else:
            returncode = 'Im here'

def main():
    upobj = Uploader()
    returncode = upobj.upload()

    if returncode == '100':
        print "Success!"
    else:
        print "Maybe a Fail"
        print returncode
    print "The End"

if __name__ == '__main__':
main()
7
задан Community 23 May 2017 в 12:09
поделиться