I am going to run the WEBQQ alone, a direct copy of the PYXMPP2 Mainloop, but run up a lot of problems, so I studied the use of Tornado Network programming (here), so I gave up Pyxmpp2 Mainloop, Using Tornado to override
First release the project code
Introduction
WEBQQ protocol is a set of HTTP based QQ protocol, and the Python urllib2 library is too slow to request, because HTTP itself uses socket request, so instead of multiplexing I/O model, and tornado simple and efficient, See the code can be easy to use. Platform compatibility is good, so choose Tornado as the network framework.
principle
First implemented a Httpstream class, its main interface is the Add_request method, it accepts a required parameter: request is a urllib2. instance of request, and an optional parameter: Readback is a read function that accepts the response parameter returned by a urllib2.urlopen (request) with the following code:
Class Httpstream (object):
# omits several code
def add_request (self, request, readback = None):
If not isinstance ( Request, Urllib2. Request):
raise ValueError, "not a invaid requset"
# here easily triggers timeout exception, omit handling exception code
sock, data = Self.http_ Sock.make_http_sock_data (Request)
FD = Sock.fileno ()
self.fd_map[fd] = sock
SELF.FD_REQUEST_MAP[FD] = Request
callback = partial (self._handle_events, request, data, readback)
Self.ioloop.add_handler (FD, Callback, Ioloop.write)
Httpstream.add_request will urllib2. The instance of request resolves a socket and a data that is sent for the socket. The previous article describes the Tornado.ioloop.IOLoop.add_handler for registering the socket, which requires three parameters: The file descriptor for the socket, which accepts callback for file description and event parameters, and registered events.
The callback we use is httpstream._handle_events:
Class Httpstream (object): # omits several code def _handle_events (self, request, data, Readback, FD, Event): "" For handling Tornado matters Piece Arguments: ' Request '-urllib.
Request ' data '-' readback ' to write to the socket-read function The above parameter should use the partial encapsulation and then take this method as Ioloop.add_handler callback ' FD '-ioloop Pass file Descriptor ' event '-Ioloop pass Tornado "" "s = self.fd_map[fd] If event & I Oloop.read: # omit error Handling RESP = Self.http_sock.make_response (s, request) args = Readback (resp) s.setbl Ocking (False) if args and Len (args) = = 3:t = Threading. Thread (target = self.add_delay_request, args = args) T.setdaemon (True) T.start () if args and Len (AR GS) = = 2:self.add_request (*args) Self.ioloop.remove_handler (FD) if event & IOLOOP.WRITE:S.S Endall (data) if Readback:self.ioloop.update_handler (FD, Ioloop.read) else:self.ioloop.remove _handler (FD) if event & IOLoop.ERROR:pass
The parameters it accepts are written very clearly and do not explain, so pass this method through Functools.partial encapsulation as callback to Tornado.ioloop.IOLoop.add_handler and register as a write event, To send an HTTP request.
Httpstream._handle_events is used to handle events, sending HTTP requests when the event is write (according to URLLIB2. The data that the request generates for sending), and to determine whether there are read functions, there are registered read events, when the event is read from the socket to build a response and passed to the Read function, the reading function will return 3 values, respectively: The next request, the requested read function (can be none, None only requests no read), delay of the next request (add this request after a long event, optional, in seconds)
Determines the next request based on the three values returned by the Read function, and completes a series of requests. For more complete code, see the project code given at the beginning of the article
When HTTPStream.http_sock.make_response executes, the socket is set to block because Httplib is present when blocking is not set. Badstatusline exception. The read function completes, the socket is reset to non-blocking, and the socket is removed (although this is done but the QQ connection time is slightly longer or triggers the httplib.badstatusline exception)