Write it before you start

What is a Web server?

A Web server, as the name implies, is a server that provides Web services, and what we are going to do here is exactly a server program

Why write a Web server?

Just for fun

What are the basics needed to understand this passage?

    • You can understand python3’s basic syntax

The official start of the

Import socket # service port try: HttpPort = int(input('Please input the server port, default port is 9420:')) except Exception as e: HttpHost = ('localhost', HttpResponseHeader = "" HTTP/1.1 200 OK content-type: Socket = socket. Socket (socket.AF_INET, ListenSocket. Bind (HttpHost) ListenSocket. Listen (100) LineSeparator = '\r\n\r\n' print('The server is running on port %d' % HttpPort) print('The url is http://localhost:%d' % HttpPort) while  True: HttpResponseBody = 'Hi : )' Client, Address = ListenSocket.accept() Request = Client.recv(1024).decode(encoding='utf-8') Client.sendall((HttpResponseHeader + HttpResponseBody).encode(encoding='utf-8')) Client.close()Copy the code

This, what did not say, up on the code, is not too appropriate ah? Let’s try it out first, and then understand how this code works.

We save the above code as a fileweb_server.pyAnd run in the terminalpython web_server.py

Then enter the server port number, then open copy the following URL and paste it into the browser for access, you can see the effect





You’ll notice the top oneimpoet socketIn other words, we need to use the socket package to complete our server program.

First set up a socket, bind it to a port on our machine, in this case I set the default port to 9420, and then start listening on that port. The next cycle is to accept a socket connection each time, save the information for the Client, which is the binding for the Client, send some data to the Client, break the connection, and then accept the next Client request.

What about web servers? I haven’t seen the web for a long time, but I’ve been talking about sockets. What is socket?

We can understand socket as the TCP/IP protocol family of the upper implementation, that is to say, there is a standard, but the standard is only the standard, the standard is used to guide and provisions, or need specific implementation, here socket is the implementation of this standard, we said this article web server is mainly HTTP, no longer say HTTPS, Web sockets and more.

HTTP is based on THE TCP protocol, but added some attributes to TCP and further abstracted and encapsulated, that is to say, when we use HTTP for data transmission, TCP is also connected, in the connection process we need to use socket.

HTTP requests and responses are in the form of headers and subjects, separated by a blank line, which is also the basis of our segmentation. If you’re interested in MDN documentation, first the browser sends a request to the server, and then the server receives the request, and then it returns a piece of text to the browser, and the browser parses that text and displays it to us.

Our HttpResponse is simply a header that needs to be returned to the client. Without this, the browser will not parse it, which is an invalid response.

If you change the URL in your browser, you’ll find that the server will only return a Hi, so let’s look at the next section.

Small refinements

Well, we didn’t implement anything except Hi, we just implemented GET, and then we implemented getting the parameters of the user’s request, getting the header of the user’s request, getting the method of the user’s request, and getting the POST form, again, directly into the code.

Import socket # service port try: HttpPort = int(input('Please input the server port, default port is 9420:')) except Exception as e: HttpHost = ('localhost', HttpResponseHeader = "" HTTP/1.1 200 OK content-type: Socket = socket. Socket (socket.AF_INET, ListenSocket. Bind (HttpHost) ListenSocket. Listen (100) LineSeparator = '\r\n\r\n' print('The server is running on port %d' % HttpPort) print('The url is http://localhost:%d' % HttpPort) # Def get_headers(request): Headers_arr = request.split('\r\n') headers = {} for item__ in headers_arr[1:]: Split (': ') headers[item_[0]] = item_[1] return headers # def get_post_args(request_body): post_args_arr = request_body.split('&') post_args = {} for item__ in post_args_arr: item_ = item__.split('=') post_args[item_[0]] = item_[1] return post_args while True: # listen to the link Client Request = client.recv (1024). Decode (encoding=' UTF-8 ' RequestText = request.split (LineSeparator) # RequestHeader = RequestText[0] # RequestBody = RequestText[1] # RequestMethod = requestheader.split (" ")[0] # RequestUrl = requestheader.split (" ")[1] # RequestMethod = RequestHeader Get_headers (RequestHeader) # HttpResponseBody = "print(Request) # Request method == 'GET': HttpResponseBody += '<html>' HttpResponseBody += 'Your method is GET and your request url is ' + RequestUrl + '<br>' HttpResponseBody += 'Following are you headers :<br>********************************************<br>' for item in RequestHeaders.items(): HttpResponseBody += ('<list>' + item[0] + ' => ' + item[1] + '</list><br>') HttpResponseBody += '<br><br>The next is post test <br>' HttpResponseBody += ''' <form action="/" method="post"> <p>Text1: <input type="text" name="Text1" /></p> <p>Text2: <input type="text" name="Text2" /></p> <input type="submit" value="Submit" /> </form> ''' HttpResponseBody += '</html>' Elif RequestMethod == 'POST': HttpResponseBody += '<html>' HttpResponseBody += 'Your method is POST and your request url is ' + RequestUrl + '<br>' HttpResponseBody += 'Following are your headers :<br>********************************************<br>' for item in RequestHeaders.items(): HttpResponseBody += ('<list>' + item[0] + ' => ' + item[1] + '</list><br>') HttpResponseBody += 'Following is your form :<br>********************************************<br>' PostArgs = get_post_args(RequestBody) for item in PostArgs.items(): HttpResponseBody += ('<list>' + item[0] + ' => ' + item[1] + '</list><br>') HttpResponseBody += '<br><br>The next is get  test <br>' HttpResponseBody += '<a href="http://' + RequestHeaders['Host'] + '/">get test</a>' HttpResponseBody += '</ HTML >' # other methods not currently supported else: HttpResponseBody += '<html>' HttpResponseBody += 'So sorry this method is not support :(' HttpResponseBody += '</html>' Client.sendall((HttpResponseHeader + HttpResponseBody).encode(encoding='utf-8')) Client.close()Copy the code

I went from 30 lines to 120 lines, so it’s a little bit of code, so don’t worry, let’s take a look at it.

Compared to the previous section, we have added two functions, one to get the user’s request header and the other to get the form submitted by the user.

The request header format is as follows:

GET/HTTP / 1.1 Accept: text/HTML and application/XHTML + XML, application/XML. Q = 0.9 * / *; Q =0.8 Accept-encoding: gzip, deflate Accept-language: zh-cn,zh; Q = 0.8, useful - TW; Q = 0.7, useful - HK; Q = 0.5, en - US; Q = 0.3, en. Q =0.2 cache-control: max-age=0 Connection: keep-alive Host: localhost:9420 Referer: http://localhost:9420/ upgrade-insecure -Requests: 1 User-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; The rv: 59.0) Gecko / 20100101 Firefox 59.0Copy the code

We split it according to this format and give it to the browser as a response

POST request method is not limited to text submission, we only implement simple form submission here, the form submitted by POST is in the request Body, we split, and according to its format to parse, and returned to the browser as the corresponding, GET request



POST requests and gets the POST form parameters

The GET return that we’ve implemented is going to have a POST test, and after the POST is submitted, there’s going to be a GET test under the new page that comes back, and this section is not too hard, so you can open up your browser, chrome or Firefox, open up the developer window with F12, and look at the information being transferred. Let’s look at the next section.

In a further step

Our server corresponding web pages are written in the server code, change a web page also have to modify the server code, too inconvenient, in reason, so do not appropriate, so this time we try to send HTML files to the user, and achieve the transmission of pictures.

Import socket # service port try: HttpPort = int(input('Please input the server port, default port is 9420:')) except Exception as e: HttpHost = ('localhost', HttpHtmlResponseHeader = "" HTTP/1.1 200 OK content-type: Text/HTML "" HttpImageResponseHeader =" "HTTP/1.1 200 OK content-type: HttpResponseBody = "HttpResponse =".encode(encoding=' utF-8 ') # socket.socket(socket.AF_INET, ListenSocket. Bind (HttpHost) ListenSocket. Listen (100) LineSeparator = '\r\n\r\n' print('The server is running on port %d' % HttpPort) print('The url is http://localhost:%d' % HttpPort) # Def get_headers(request): Headers_arr = request.split('\r\n') headers = {} for item__ in headers_arr[1:]: Split (': ') headers[item_[0]] = item_[1] return headers # def get_post_args(request_body): post_args_arr = request_body.split('&') post_args = {} for item__ in post_args_arr: item_ = item__.split('=') post_args[item_[0]] = item_[1] return post_args while True: # listen to the link Client Request = client.recv (1024). Decode (encoding=' UTF-8 ' RequestText = request.split (LineSeparator) # RequestHeader = RequestText[0] # RequestBody = RequestText[1] # RequestMethod = requestheader.split (" ")[0] # RequestUrl = requestheader.split (" ")[1] # RequestMethod = RequestHeader Get_headers (RequestHeader) # return HttpResponseBody = "" HttpResponse =". Encode (encoding=' utF-8 ') # GET method to handle if RequestMethod == 'GET': # if RequestUrl[-1] == '/': If the Url ends with a /, Print (RequestUrl) # webpage if requesturl.split ('.')[-1] == 'HTML ': try: Res = open('.' + RequestUrl, 'rb') StaticHtml = res.read() HttpResponse += HttpHtmlResponseHeader.encode(encoding='utf-8') HttpResponse += (HttpResponseBody.encode(encoding='utf-8') + StaticHtml) res.close() except Exception: HttpResponse += HttpHtmlResponseHeader.encode(encoding='utf-8') HttpResponse += '<html><br>ERROR ! < br > < / HTML > '. The encode (encoding = "utf-8") # image elif RequestUrl. Split ('. ') [1] = = 'JPG' : try: res = open('.' + RequestUrl, 'rb') ImageFile = res.read() HttpResponse += HttpImageResponseHeader.encode(encoding='utf-8') HttpResponse += (HttpResponseBody.encode(encoding='utf-8') + ImageFile) res.close() except Exception: HttpResponse += HttpImageResponseHeader.encode(encoding='utf-8') HttpResponse += ''.encode(encoding='utf-8') HttpResponse += '<br><br>The next is post test <br>'.encode(encoding='utf-8') HttpResponse += ''' <form action="/" method="post"> <p>Text1: <input type="text" name="Text1" /></p> <p>Text2: <input type="text" name="Text2" /></p> <input type="submit" value="Submit" /> </form> '''.encode(encoding='utf-8') # Elif RequestMethod == 'POST': HttpResponseBody += '<html>' HttpResponseBody += 'Your method is POST and your request url is ' + RequestUrl + '<br>' HttpResponseBody += 'Following are your headers :<br>********************************************<br>' for item in RequestHeaders.items(): HttpResponseBody += ('<list>' + item[0] + ' => ' + item[1] + '</list><br>') HttpResponseBody += 'Following is your form :<br>********************************************<br>' PostArgs = get_post_args(RequestBody) for item in PostArgs.items(): HttpResponseBody += ('<list>' + item[0] + ' => ' + item[1] + '</list><br>') HttpResponseBody += '<br><br>The next is get  test <br>' HttpResponseBody += '<a href="http://' + RequestHeaders['Host'] + '/">get test</a>' HttpResponseBody += '</ HTML >' HttpResponse += (HttpHtmlResponseHeader + HttpResponseBody).encode(encoding=' utF-8 ') # HttpResponse = (HttpHtmlResponseHeader + 'So sorry this method is not support :(').encode(encoding='utf-8') Client.sendall(HttpResponse) Client.close()Copy the code

In pages, create an index. HTML file and a pic.jpg image

<html>
<a href="/pages/">Pages</a>
</html>Copy the code

Index.html is defined when accessing the home page

Then jump to pages and load /pages/index.html

<html>
Show me the image<br>
<img src="pic.jpg"/>
</html>Copy the code

/pages/index.html has a reference to the image, and the browser continues to request the image, and the server reads the image and responds. At this point we have finished reading the static page and displaying the image.



The next step?

We can accept browser requests and respond to browser text and images, get POST forms, but it is still relatively simple, need to add a lot of features, such as support for file upload, support for multi-user requests and so on.

Now, go in this direction.