Parse socket communication with Python SimpleHTTPServer source code. simplesocketserver
What is socket
Computers, as the name implies, are used for computing. Therefore, the input and output are also required. The input must be calculated and the calculation result is output. These input and output can be abstracted as I/O (input output ).
Unix computers process IO through file abstraction. Different processes on the computer also have input and output, that is, communication. Therefore, this communication is carried out through the abstract file descriptor of the file.
On the same computer, processes can communicate in this way. What if they are different computers? Different computers on the network can also communicate with each other, so you must use a network socket ). Socket is an abstraction for communication between different computers. It is an abstraction between the application layer and the transport layer in TCP/IP. For example:
Server Communication
Socket ensures communication between different computers, that is, network communication. For websites, the communication model is communication between client servers. Both ENDS create a socket object and transmit data through the socket object. Generally, the server is in a wireless loop, waiting for client connection:
Socket Communication instance
The socket interface is provided by the operating system and called the interface of the operating system. Of course, advanced languages also encapsulate easy-to-use function interfaces. Below is a simple socket server example written using python code:
Server. py
Import socketHOST = 'localhost' # server host address PORT = 5000 # server listening PORT BUFFER_SIZE = 2048 # Read data size # create a socket sock = socket. socket (socket. AF_INET, socket. SOCK_STREAM) # bind the host and port sock. bind (HOST, PORT) # enable socket listener sock. listen (5) print 'server start, listening {}'. format (PORT) while True: # establish a connection. When the connection is established, conn and addr = sock are blocked. accept () while True: # Read data. data has not been blocked yet. data = conn. recv (BUFFER_SIZE) if len (data): print 'server Recv Data :{}'. format (data) conn. send (data) print 'server Send Data :{}'. format (data) else: print 'server Recv Over 'break conn. close () sock. close ()
Client. py
Import socketHOST = 'localhost' PORT = 5000BUFFER_SIZE = 1024 # create a client socket sock = socket. socket (socket. AF_INET, socket. SOCK_STREAM) # connect to the server sock. connect (HOST, PORT) try: message = "Hello" # initiate data to the server sock. sendall (message) amount_received = 0 amount_expected = len (message) while amount_received <amount_expected: # receive data returned by the server = sock. recv (10) amount_received + = len (data) print 'client Received ed :{}'. format (data) socket T. errno, e: print 'socket error :{}'. format (e) failed t Exception, e: print 'other exception: % s '. format (e) finally: print 'closing connection to the Server' sock. close ()
TCP three-way handshake
Writing a socket in python code is simple. How is the legendary TCP three-way handshake reflected? What is a three-way handshake?
Grip 1: first, the client sends a syn and requests a connection,
Second hold: the server will confirm after receiving the message and send a syn ack response
Third, the client will send a connection confirmation to the server after receiving a response from the server.
The following is a metaphor:
C: about?
S: About
C: Okay.
Appointment
In this way, a TCP connection session is established. To disconnect a connection, the general process is as follows:
It also clearly shows the specific process of the three-way handshake socket.
- The client socket object is blocked after connect is called. A syn is sent during this process.
- The server socket object is blocked after the accept function is called until the syn sent by the client and then the syn and ack responses are sent.
- After receiving a response from the server, the client socket object sends an ack to the server and returns a connect call to establish a connection.
- The server socket object accepts the client's last handshake to confirm the ack and returns the accept function to establish a connection.
So far, the socket communication connection between the client and the server has been established, and the rest is that the connection objects of the two terminals send and receive data to complete network communication.
SimpleHTTPServer
To build a simple HTTP service, you must inherit HTTPServer and requesthandler must also inherit BaseHTTPRequestHandler. Python has implemented an example, SimpleHTTPServer. Therefore, we analyze SimpleHTTPServer to see how to use the previous classes to build http Services.
For the sake of simplicity and elegance of python, it is often used as an example that python can enable a server with a line of code.
$ python -m SimpleHTTPServer
SimpleHTTPServer is the module that implements HTTPServer.
SimpleHTTPServer uses the test method of the BaseHTTPServer module as the portal.
def test(HandlerClass = SimpleHTTPRequestHandler, ServerClass = BaseHTTPServer.HTTPServer): BaseHTTPServer.test(HandlerClass, ServerClass)
The test method does two things. The first thing is to use HTTPServer to accept a listening address and the requestClass parameter, create an instance object, and call the server_forever method to enable the Service.
1. SimpleHTTPRequestHandler
Based on the previous analysis, we only need to continue with BaseHTTPRequestHandler and provide a method for introspection to use the httpserver service.
class SimpleHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler): server_version = "SimpleHTTP/" + __version__ def do_GET(self): f = self.send_head() if f: self.copyfile(f, self.wfile) f.close() def do_HEAD(self): f = self.send_head() if f: f.close()
Do_GET and do_HEAD implement http get requests and head requests respectively. They call the send_head method:
def send_head(self): path = self.translate_path(self.path) f = None if os.path.isdir(path): if not self.path.endswith('/'): self.send_response(301) self.send_header("Location", self.path + "/") self.end_headers() return None for index in "index.html", "index.htm": index = os.path.join(path, index) if os.path.exists(index): path = index break else: return self.list_directory(path) ctype = self.guess_type(path) try: f = open(path, 'rb') except IOError: self.send_error(404, "File not found") return None self.send_response(200) self.send_header("Content-type", ctype) fs = os.fstat(f.fileno()) self.send_header("Content-Length", str(fs[6])) self.send_header("Last-Modified", self.date_time_string(fs.st_mtime)) self.end_headers() return f
The send_head method analyzes the uri path to obtain the network path requested by the customer. Construct the mime metadata of the head and send it to the client. Then, return a file handle that opens the path.
2. copyfile
The next step of do_GET is to write the file data of the path requested by the customer to the buffer writable file and send it to the client through the copyfile method.
3. list_directory
The SimpleHTTPServer module also provides the list_directory method to respond to the situation where path is a directory rather than a file.
def list_directory(self, path): try: list = os.listdir(path) except os.error: self.send_error(404, "No permission to list directory") return None list.sort(key=lambda a: a.lower()) f = StringIO() displaypath = cgi.escape(urllib.unquote(self.path)) f.write('<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">') f.write("
Therefore, to process client requests, you only need to use send_reponse, send_header, and end_headers to send reponse to the client.
4. Custom http service
Define a CustomHTTPRequestHadnler inherited from BaseHTTPRequestHandler. Implement the do_GET method in it to process get requests.
Then define a CustomHTTPServer inherited from HTTPServer, which accepts CustomHTTPRequestHadnler as its own handler. The simple code is as follows:
# -*- coding: utf-8 -*-from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServerclass CustomHTTPRequestHandler(BaseHTTPRequestHandler): def do_GET(self): self.send_response(200) self.send_header('Content-type', 'text/html') self.end_headers() self.wfile.write("hello world\r\n")class CustomHTTPServer(HTTPServer): def __init__(self, host, port): HTTPServer.__init__(self, (host, port), CustomHTTPRequestHandler)def main(): server = CustomHTTPServer('127.0.0.1', 8000) server.serve_forever()if __name__ == '__main__': main()
Use curl to obtain
➜ ~ curl http://127.0.0.1:8000hello world➜ ~
The console displays the accessed log.
127.0.0.1 - - [01/Jun/2015 11:42:33] "GET / HTTP/1.1" 200 -
From the establishment of socket, select IO mode, to the combination of Server and Handler to build services. We are familiar with python's basic network programming. In python web development, the WSGI protocol is used. UWSGI and gunicorn libraries are also implemented for this Protocol. Compared with those libraries, python provides a wsgiref module to implement a simple wsgi service-simple_server.
Next, we will analyze simple_server to better master the WSGI protocol.