当编写网络应用程序时,比如我们前面章节里的回显客户端,都是用 socket 库来读写客户端数据。虽然直接使用 socket 在构建底层网络库时很有用,但它们本质上是复杂的东西,有很多细节超出了本书的范围。不过,很多 socket 的应用场景其实依赖于几个概念上很简单操作,比如启动服务器、等待客户端连接、向客户端发送数据。asyncio 的设计者们意识到这一点,并为我们构建了网络流接口,帮我们把处理 socket 复杂性的部分抽象掉了。这些高层级的接口比直接操作 socket 容易太多,使得构建客户端/服务器应用变得更轻松也更健壮。因此,在 asyncio 中,推荐使用流来开发基于网络的应用。
本章我们将先学习使用底层的传输和协议接口,通过构建一个简单的 HTTP 客户端来掌握其原理。了解这些接口能帮助我们理解高层级流接口在后台是如何工作的。接着,我们会利用这些知识学习流读写器,并用它们构建一个非阻塞的命令行 SQL 客户端。这个应用能异步处理用户输入,让你能在命令行中并发运行多个查询。最后,我们还会学习如何使用 asyncio 的服务器接口来创建客户端和服务器应用,最终搭建一个功能完整的聊天服务器和聊天客户端。
在 asyncio 里,流(streams) 是一组高级类和函数,用于创建和管理网络连接以及通用的数据流。借助它们,我们可以创建连接到服务器的客户端来读写数据,甚至可以自己创建服务器并管理它。这些接口隐藏了很多关于管理 socket 的细节,比如处理 SSL 或断开连接的问题,让开发者的生活轻松不少。
流接口建立在更低层的 传输(transports) 与 协议(protocols) 接口之上。这些接口直接封装了我们在前几章用过的 socket(通常是任意的数据流),为我们提供了一个干净的、用于读写数据到 socket 的接口。
这些接口的设计与其他方式略有不同,采用的是回调风格。不同于以前主动等待来自 socket 的数据,而是当有数据可读时,系统会自动调用我们实现类中的某个方法。我们再在这个方法里按需处理接收到的数据。为了更好地理解这种基于回调的接口,让我们先来看如何用底层的传输和协议接口来构建一个基本的 HTTP 客户端。