Tornado's core source code is made up of the 2 files of ioloop.py and iostream.py. The former provides a loop for handling I/O events, while the latter encapsulates a non-blocking socket.
With these 2, you can build TCP server and HTTP server to implement asynchronous HTTP client, this is the main content of tornado.
Before the study of the socket has almost understood the logic of the Ioloop, so this article will then study the iostream.
I don't want to analyze iostream's source code by line, because it's not something that's hard to understand, so just say what it does.
First look at the iostream __init__ () method, the important parameters are only socket and io_loop these 2. So it's easy to guess that it just encapsulates the socket and then registers the I/O event on the Io_loop.
Read the source code can quickly confirm our guess, it is worth noting that the encapsulation socket also set it as non-blocking.
The _add_io_state () method is invoked after the connection and read and write, which means that the Io_loop Add_handler () and Update_handler () methods are invoked to register the event.
In addition, there seems to be no open interface to read all the data, and you can use the _read_to_buffer () method to implement it yourself.
Read the source may or confused, it can be used to do what.
The most important use of course is to achieve tcpserver. With Ioloop, a server can handle I/O events, but I/O is not created in a vacuum, it also needs to connect and transfer through the socket.
And as mentioned earlier, iostream encapsulates the socket, turns it into non-blocking, and registers the I/O events with each connection and read and write to the Io_loop, thus achieving a complete tcpserver.
Unfortunately tornado source code in the TCPServer does not have the actual function, Httpserver is too complex, so I found a section of the Echo server, a look to know to use. The test is also very simple, with telnet connected up, input what will be back to what.
Another feature is associated with non-blocking.
Tornado can handle high concurrency in a single thread, relying on non-blocking. If any one of the I/O is non-blocking and consumes milliseconds or even seconds, the number of requests that can be processed per second cannot exceed 1000.
So these time-consuming, long I/O accesses must be encapsulated as non-blocking, and this is iostream done long ago.
In addition, asynchronous processing is needed to improve the responsiveness of the service.
The chat room I wrote a few days ago, for example, when a user sends a message, I need to broadcast it to all the users before I can end this response.
In this example, the user may not have to wait long. But if I still need to do some complex processing, such as keyword filter, analysis @ user name, URL, save to the database, or send email, etc., I do not want to let the user's request has been blocked.
Then I can build another tcpserver, send the received information through iostream to it, and then immediately end the response. In that tcpserver, I want to do any time-consuming thing, will not slow down the main httpserver response speed, and once the processing, you can return the result through iostream to Httpserver, let it complete the cleanup work.
Still, for example, in a chat room, when I receive the information, I send it to echoserver and end the response.
Echoserver returns the input information, at which time Httpserver hears the event and reads and broadcasts the message.
Although for the user, the effect is the same. However, the overall system extensibility is enhanced, you can replace this echoserver into message queues, memcache and other data sources. Although there are still great differences in implementation, the most important idea is the same.
The code is about the same as the last chat room, and the handler part is the same, so I just post the change section:
Import logging
Import Os.path
Import socket
Import UUID
Import Tornado.httpserver
Import Tornado.ioloop
Import Tornado.iostream
Import Tornado.options
Import Tornado.web
Import Tornado.websocket
def broadcast_message (message):
For handler in Chatsockethandler.socket_handlers:
Try
Handler.write_message (Message)
Except
Logging.error (' Error sending message ', exc_info=true)
For callback in Chathandler.callbacks:
Try
Callback (Message)
Except
Logging.error (' Error in callback ', Exc_info=true)
Chathandler.callbacks = set ()
def send_message (message):
Stream.Write (message + ' \ n '). Encode (' Utf-8 ')
Def read_message_from_echo_server ():
DEF broadcast (message):
Broadcast_message (Message[:-1])
Read_message_from_echo_server ()
Stream.read_until (' \ n ', broadcast)
# ...
if __name__ = = ' __main__ ':
s = socket.socket (socket.af_inet, socket. Sock_stream, 0)
Stream = Tornado.iostream.IOStream (s)
Stream.connect ((' 127.0.0.1 ', 8888))
Read_message_from_echo_server ()
Main ()
Note that the connection Echoserver needs to be preceded by a call to the Ioloop start () method, because the method is a dead loop, and the following code has no chance of executing.