基于协程的简单Web Server

393 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第7天,点击查看活动详情

Python3 中提供了async 和 await 关键字,为异步的编程带来了相当大的便利。本文的目的是使用比较底层的接口实现一个简单的Web Server.

最基本的思路如下: 使用一个socket监听接受新的连接,对于每个到来的请求,放入事件队列进行调度处理。

对于每个到来请求的处理,通过使用协程处理,避免大量的线程浪费。借助 asycn 和 await 以近乎同步的方式,完成异步代码的书写。

监听端口的 socket 处理

对于这个套接字对象,我们的方法是借助 Python 协程事件循环给出的处理非阻塞套接字的方法接受请求。无限循环这个操作,并将该过程一同交由调度器调度

while True:
            client, _ = await loop.sock_accept(server)\
            loop.create_task(handle_client(client))

将该代码实现为异步函数。

对于到来的请求处理

同样的借助事件循环提供的异步读取操作,以避免阻塞主线程。

await loop.sock_recv(sock)

对于HTTP请求,主要的过程在于处理请求头,对于GET和HEADER这种的请求,只要读取首行即可(如果不处理长连接请求之类的话),而对于post和put等其他请求实际上相当麻烦,因为现在基本上http中的这些请求都是使用MIME类型的扩展,所以这里没能具体实现。

于是我们的处理函数大致如下:

async def handle_client(chan):\
    by = (await loop.sock_recv(chan, 2048)).decode("utf-8")\
    requestUrl = by.split()[1]
    # 具体的处理操作,读取文件等

整体上整个程序的重点在于让程序的中awaitable对象在await操作时进入调度队列,以使得它可以避免使用无意义的等待时间。

目前相当多的语言在协程上发力,如日中天的Java正在孵化loom项目,甚至许多新特性都在为它让路。C++ 20 推出了最原始的协程概念,在未来的两个版本中势必会推出更加用户友好的协程接口,而且C++也将迎来官方的网络库,实属一大奇观。 协程的未来一片光明。