引  言

经过20年来的严谨创新,Python在引入了诸如上下文管理器(context manager)、生成器(generator)以及推导式(comprehension)等特性的同时,仍然保持了其语法及概念一贯的简洁。Python终于开始大放异彩,这对于Python社区来说,分外激动人心。

在有些人眼中,Python是一门只能被Google和NASA这种一流编程机构冒险使用的精品语言,但事实恰好相反,Python正在被广泛使用。它不仅应用于传统的编程任务,如Web应用程序设计;也被大量“被赶鸭子上架的程序员”——科学家、数据专员以及工程师所采用,他们编程并非出于兴趣,而是必须靠编程才能在自己的领域中更进一步。我认为,一门简单的编程语言为业余编程人员提供的便利是不容小觑的。

Python 3

自2008年问世以来,Python 3一直在不断修订和精简,以期承担起Python 2的角色。如今,Python 3迎来了面世以来的第二个5年,已然成为了Python社区内进行创新的首选平台。

Python 3提供给网络程序员的编程平台几乎在方方面面都有所改进,无论是基础性的(如将Unicode文本设为Python 3的默认字符串类型),还是特有的(如对SSL的正确支持、内置的用于异步编程的asyncio框架,以及对标准库中大大小小的模块的细微调整)。这是一个显著的进步。要知道, Python 2就已经是程序员在现代互联网环境中用来快速高效工作的最佳语言之一了。

本书的目的并非提供从Python 2迁移到Python 3的全面指南。本书不会讲述如何给老版本的print语句添加括号,也不会介绍如何对导入的标准库模块进行重命名,更不会讲解如何对Python 2中从字节字符串到Unicode字符串的自动转换(这一转换通常基于粗略的猜测)这一危险特性引入的缺陷代码进行深度调试。关于如何从Python 2迁移到Python 3,以及如何仔细编写能够同时支持这两个平台的代码,已经有很多优质的资源提供了相应的指导。

本书的重点在于网络编程,并且在所有示例脚本及代码片段中都使用Python 3来阐释。这些例子的目的是帮助读者全面了解使用这门语言提供的工具构建网络客户端、网络服务器以及网络工具的最佳实践。读者可以将这些例子与第2版中各章使用的脚本进行比较,以此来学习从Python 2到Python 3的迁移。两个版本的代码都可以从https://github.com/brandon-rhodes/fopnp/tree/m/获取。这要感谢Apress出版社,让我们能够从网络上获取源代码。接下来各个章节的目的就是介绍如何最大化地使用Python 3提供的功能来解决现代网络编程的问题。

本书直接把关注点放在了如何使用Python 3正确完成工作上,希望以此帮助准备从头开始编写新应用程序的程序员和准备将老版本代码移植到新规范的程序员。他们都应该了解如何使用Python 3编写出正确的网络程序代码,并清楚他们应该努力去编写的目标代码的样式和特点。

这一版的改进

这一版对以前的版本进行了更新,除了将目标语言向Python 3迁移,以及对过去5年中标准库和第三方Python模块进行了许多更新外,还在如下方面进行了改进。

 这一版列出的每个Python程序都编写成了一个模块。换言之,每个程序都会导入其依赖的模块,定义其函数或类,然后通过一个if语句来确保所有导入行为。只有在模块name为特殊字符串值'main'时,该if语句对应的代码块才会执行。模块name为'main',表示该模块作为主程序执行。这是在本书之前版本中被彻底忽略的一个Python最佳实践,使得读者无法很方便地将示例代码应用到真实的代码库中解决问题。老版本的代码清单在左边空白区域列出了执行逻辑,而没有将其放在if语句中。这样做可能会少写一两行代码,但是初学Python的程序员在部署实际代码时,能从中得到的实践指导却少了很多。

 老版本中的脚本临时使用原始的sys.argv字符串列表来解析命令行选项和参数,而这一版中的大多数脚本使用的则是标准库的argparse模块。这不仅阐明并记录了每个脚本被调用时表示的语义,还允许每个脚本的用户使用-h或者--help查询选项,在Windows或Unix的命令行中获取交互式的帮助文档。

 这一版的程序通过在with控制语句中打开文件来进行合理的资源控制。with语句包含的代码块完成的时候,打开的文件会自动关闭。在之前的版本中,大多数程序并不会这样做,而是依赖于C Python的运行时服务。Python的官方网站提供的C Python通过严格的引用计数机制,通常可以确保打开的文件能够及时关闭。

 大多数程序在进行字符串插值时已经转而使用现代的format()方法,以前则使用string % tuple的方法。后者在20世纪90年代有一定的意义,因为那时大多数程序员都通晓C语言。但对于现在进入这个领域的新人程序员来说,这种方法可读性较差,而且由于自定义的Python类不能对百分号格式符进行操作符重载,因此提供的功能也不够强大。

 重写了关于HTTP和万维网的3章(第9章至第11章),侧重于更清晰地解释协议,并介绍Python所提供的大部分用于编写Web应用的现代工具。这一版在解释HTTP协议时使用Requests库进行客户端操作,它提供的API相当实用。第11章提供了Flask和Django框架的示例。

 Python 3大量改进了为编写安全的应用程序所提供的支持,所以这一版彻底重写了关于SSL/TLS(第6章)的内容。Python 2的ssl模块使用的是一个折中的方法。该方法功能较弱,甚至没有验证服务器的证书是否与Python连接的主机名对应。因此,Python 3的ssl模块提供了一个设计更严谨、功能更丰富的API,以便用户安全方便地使用其特性。

因此,对于渴望不断学习的程序员来说,且不论Python 3本身所做出的改进,单论代码清单以及示例的构建,这一版相较以前的版本也绝对是更好的资源。

网络实验环境

本书给出程序的源代码可在网上获取,因此本书所有者及想要阅读本书的读者均可访问网络资源进行学习。读者可以从如下网址找到本书各章的代码目录:

https://github.com/brandon-rhodes/fopnp/tree/m/py3

然而对于对网络编程充满好奇的学生来说,本书给出的代码清单所能提供的帮助仍然是有限的。如果只在单机上进行实验,那么网络编程的很多特性都无法得到体现。因此,本书的程序库也提供了一个由12台机器组成的网络实验环境,每台机器通过一个Docker容器实现。程序库同样包含了一个安装脚本,用来构建、启动以及连接各容器的镜像。读者可从如下地址找到该安装脚本以及容器镜像:

https://github.com/brandon-rhodes/fopnp/tree/m/playground

图0-1展示了这12台机器以及它们的连接架构。该网络的设计目的是模拟一个小型的互联网。

enter image description here

 调制解调器A和B下面的客户机(h1到h4)表示典型的客户端场景,如家庭或咖啡店。这些客户机不向互联网提供服务。事实上,它们对外部网络是完全不可见的。它们与同一家庭或咖啡店环境内的其他主机共享子网,只拥有在这些子网内才有意义的本地IP地址。当这些客户机连接外网时,其实都是通过调制解调器的IP地址进行连接的。

 调制解调器可通过一个ISP网关与更广域的网络直接相连。实验环境中的广域网由一个主干路由器表示,该路由器负责将数据包发送至与之相连的网络。

 example.com及与之相连接的机器表示一组简单的面向服务的机房配置。这里没有进行任何网络地址转换或伪装。互联网上的各个客户端可随意访问example.com后的3个服务器提供的服务端口。

 ftp服务器、mail服务器和www服务器中的任意一个都运行着正确配置的守护进程。因此,本书中的Python脚本也可以运行在其他机器上,并成功连接到上述服务。

 所有服务器均已成功安装TLS证书(见第6章),而所有客户机则有example.com的签名认证,并安装了受信证书。这意味着要求TLS认证的Python脚本可以成功获取认证。

随着Python和Docker的不断优化,我们也会持续维护网络实验环境。关于如何下载并在本机上运行该网络实验环境的使用说明会不断更新,也会根据用户的使用报告进行微调,以保证读者可以在Linux、Mac OS X以及Windows机器上运行该实验环境的虚拟机。

由于可以在网络实验环境的任意一台机器上连接并运行命令,读者可对网络中的任意一个点进行数据包追踪,查看客户端和服务器之间的网络数据传输情况。通过文档中的示例代码以及本书中的例子和使用说明,读者可以深刻、生动地理解客户端与服务器是如何通过网络进行通信的。

目录

  • 引  言
  • 致  谢
  • 第1章 客户端/服务器网络编程简介
  • 第2章 UDP
  • 第3章 TCP
  • 第4章 套接字名与DNS
  • 第5章 网络数据与网络错误
  • 第6章 TLS/SSL
  • 第7章 服务器架构
  • 第8章 缓存与消息队列
  • 第9章 HTTP客户端 
  • 第10章 HTTP服务器 
  • 第11章 万维网
  • 第12章 电子邮件的构造与解析
  • 第13章 SMTP
  • 第14章 POP
  • 第15章 IMAP
  • 第16章 Telnet和SSH 
  • 第17章 FTP
  • 第18章 RPC