我在 GitHub 上开源了这个系列文章的翻译版(还在跟进原作者的更新),第一次公开翻译英文教程,纯粹兴趣使然,错漏和不严谨在所难免……欢迎提出意见和建议。
? ? ?
原文:《Let’s Build A Web Server. Part 3.》
“We learn most when we have to invent” —Piaget
在 Part 2 中,您创建了一个可以处理基本 HTTP GET 请求的简约 WSGI 服务器。我问你一个问题,“你怎么能让你的服务器一次处理多个请求?”,在本文中你会找到答案。因此,抓紧扶好,老司机带你飞。真的是老司机带你飞的感觉哦。准备好Linux,Mac OS X(或任何 * nix 系统)和 Python。文章中的所有源代码都可以在 GitHub 上找到。
首先让我们回想起一个非常基本的 Web 服务器是什么样的,以及服务器需要做些什么来服务客户端的请求。您在 Part 1 和 Part 2 中创建的服务器是一个迭代服务器,一次处理一个客户端请求。在完成处理当前客户端请求之前,它不能接受新的客户端连接。有些客户可能对它不满意,因为他们必须排队等候,对于繁忙的服务器,这个等待队列可能会很长。
下面是迭代服务器 webserver3a.py
的代码:
#####################################################################
# Iterative server - webserver3a.py #
# #
# Tested with Python 2.7.9 & Python 3.4 on Ubuntu 14.04 & Mac OS X #
#####################################################################
import socket
SERVER_ADDRESS = (HOST, PORT) = '', 8888
REQUEST_QUEUE_SIZE = 5
def handle_request(client_connection):
request = client_connection.recv(1024)
print(request.decode())
http_response = b"""\
HTTP/1.1 200 OK
Hello, World!
"""
client_connection.sendall(http_response)
def serve_forever():
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind(SERVER_ADDRESS)
listen_socket.listen(REQUEST_QUEUE_SIZE)
print('Serving HTTP on port {port} ...'.format(port=PORT))
while True:
client_connection, client_address = listen_socket.accept()
handle_request(client_connection)
client_connection.close()
if __name__ == '__main__':
serve_forever()
译者注:原作者还没有更新 Part 3 的代码,所以这部分的代码我暂时没有自己验证,等待原作者的更新吧。。
想要观察这个服务器一次只处理一个客户端请求的情况,可以稍微修改服务器代码,在它向客户端发送响应后添加 60 秒的延迟。只需更改一行代码告诉服务器进程休眠60秒。
这是睡眠服务器 webserver3b.py
的代码:
#########################################################################
# Iterative server - webserver3b.py #
# #
# Tested with Python 2.7.9 & Python 3.4 on Ubuntu 14.04 & Mac OS X #
# #
# - Server sleeps for 60 seconds after sending a response to a client #
#########################################################################
import socket
import time
SERVER_ADDRESS = (HOST, PORT) = '', 8888
REQUEST_QUEUE_SIZE = 5
def handle_request(client_connection):
request = client_connection.recv(1024)
print(request.decode())
http_response = b"""\
HTTP/1.1 200 OK
Hello, World!
"""
client_connection.sendall(http_response)
time.sleep(60) # 休眠并阻塞进程60秒钟
def serve_forever():
listen_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
listen_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
listen_socket.bind(SERVER_ADDRESS)
listen_socket.listen(REQUEST_QUEUE_SIZE)
print('Serving HTTP on port {port} ...'.format(port=PORT))
while True:
client_connection, client_address = listen_socket.accept()
handle_request(client_connection)
client_connection.close()
if __name__ == '__main__':
serve_forever()
通过以下命令行启动服务器:
$ python webserver3b.py
现在打开一个新的命令行终端然后运行下面的 curl 命令。你马上就能看到打印在屏幕上的 “Hello World!”:
$ curl http://localhost:8888/hello
Hello, World!
趁热打铁再打开一个命令行终端,同样输入 curl 命令:
$ curl http://localhost:8888/hello
如果你在 60 秒内完事,那这个命令行会挂在那里不会产生任何输出。运行在第一个终端中的服务器也没有打印新的请求主体,在原作者的 Mac 上看起来就是这样(在右下角黄色框内的窗口能看到第二条 curl 命令在挂着,等待服务器接受连接):
在等待足够长时间之后(超过 60 秒),你应该会看到第一次的 curl
打印出来的 * *
UPDATE: Sat, July 13, 2019
- Updated the server code to run under Python 3.7+
- Added resources used in preparation for the article
此系列的所有文章(已翻译):