Overview
I am using urlopen from Python 2.7.1 urllib2 to create an HTTP POST on a computer running Windows XP to a remote Apache web server (e.g. Mac OS X Embedded Web Sharing). The data sent contains some identifier, data and a checksum; if all the data is sent, the server responds with a confirmation. You can use the checksum in the data to check if everything is in order.
Problem
This usually works fine, but sometimes the Internet connection is bad, often because the client sending the data uses a Wi-Fi or 3G connection. This leads to loss of Internet connection for some arbitrary time. urlopen contains a timeout parameter to make sure that this does not block your program and that it can continue.
This is what I want, but the problem is that urlopen does not stop the socket from continuing to send any data that it still had to send when the timeout occurred. I tested this (with the code that I will show below), trying to send a large bit of data to my laptop, I would see network activity in both shows, I would stop the wireless connection on the laptop, wait until the function crashes, and then repeatedly activates the wireless connection and the data transfer will continue, but the program will no longer listen to the answers. I even tried to exit the Python interpreter, and it will still send data, so Windows will somehow control this.
Causes
The timeout (as I understand it) works as follows: It checks the "standby time"
( [Python-Dev] Adding a socket timeout to urllib2 )
If you set the timeout to 3, it will open the connection, start the counter, and then try to send data and wait for a response if at some point a timer is called before receiving a response due to a timeout exception. Please note that sending data does not appear to be considered an โactivityโ in the distant timeout timer.
( urllib2 times, but does not close the socket connection )
( Close urllib2 connection )
Apparently, somewhere it is indicated that when a socket is closed / dereferenced / garbage, it calls its "close" function, which expects that all data will be sent before the socket is closed. However, there is also a shutdown function that should terminate the socket immediately, preventing any data from being sent.
( socket.shutdown vs socket.close )
( http://docs.python.org/library/socket.html#socket.socket.close )
What I want
I want the connection to be โturned offโ when a timeout occurs. Otherwise, my client will not be able to determine whether the data is received correctly or not, and try to send it again. I would rather just kill the connection and try again later, knowing that the data was (possibly) not sent successfully (the server can recognize this if the checksum does not match).
Here is the piece of code that I used to verify this. Try it ... besides the details it still doesn't work as I expected, any help there is also appreciated. As I said, I want the program to turn off the socket as soon as a timeout exception (or any other) has occurred.
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()