11. Python 网络函数
接下来我们将讨论 Python 的网络函数,这些函数使我们能够进行 TCP/IP(传输控制协议/互联网协议)编程。
![]() |
11.1. 获取互联网上某台机器的名称或 IP 地址
程序 (inet_01)
注:
- 第 1 行:Python 的网络函数封装在 socket 模块中。
结果
11.2. 一个 Web 客户端
一个用于获取网站首页内容的脚本。
程序 (inet_02)
注:
- 第 57 行:包含我们要获取其首页的网站 URL 列表。该列表存储在文本文件 [sitename.html] 中;
- 第 62 行:getIndex 函数负责执行相关操作;
- 第 4 行:getIndex 函数;
- 第 20 行:create_connection((site,port)) 方法允许您与运行在目标机器 port 端口上的 TCP/IP 服务建立连接;
- 第 35 行:send 方法允许通过 TCP/IP 连接发送数据。此处发送的是文本,该文本遵循 HTTP(超文本传输协议)协议;
- 第 40 行:recv 方法用于通过 TCP/IP 连接接收数据。此处,Web 服务器的响应以 1,000 个字符为单位分块读取,并保存到文本文件 [sitename.html] 中。
结果
Transfert reussi du paragraphe index du site istia.univ-angers.fr
Transfert reussi du paragraphe index du site www.univ-angers.fr
Transfert reussi du paragraphe index du site www.ibm.com
Echec de la connexion au site (xx,80) : [Errno 11001] getaddrinfo failed
从网站 [www.ibm.com] 接收到的文件:
- 第 1–11 行是服务器响应的 HTTP 头;
- 第 1 行:服务器指示客户端重定向至第 8 行指定的 URL;
- 第2行:响应的日期和时间;
- 第 3 行:Web 服务器标识;
- 第 4 行:服务器发送的内容。此处为从第 13 行开始的 HTML 页面;
- 第 12 行:结束 HTTP 头信息的空行;
- 第13–19行:Web服务器发送的HTML页面。
11.3. SMTP 客户端
在TCP/IP协议中,SMTP(简单邮件传输协议)是用于邮件投递服务的通信协议。
程序 (inet_03)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 | |
注:
- 在安装了杀毒软件的 Windows 计算机上,杀毒软件可能会阻止 Python 脚本连接到 SMTP 服务器的 25 号端口。因此,您必须禁用杀毒软件。以 McAfee 为例,您可以执行以下操作:
![]() |
- 在 [1] 中,打开 VirusScan 控制台
- 在 [2] 中,停止 [On-Access Protection] 服务
- 在 [3] 中,该服务已停止
结果
infos.txt 文件:
smtp.univ-angers.fr, serge.tahe@univ-angers.fr , serge.tahe@univ-angers.fr
Subject: test
ligne1
ligne2
ligne3
屏幕结果:
Thunderbird 邮件客户端显示的消息:
![]() |
11.4. 第二个 SMTP 客户端
这个第二个脚本与前一个脚本功能相同,但使用了 [smtplib] 模块的功能。
程序 (inet_04)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 | |
注:
- 除了 sendmail 函数外,此脚本与前一个完全相同。该函数现在使用了 [smtplib] 模块的功能(第 3 行)。
结果
mail2.txt 文件:
smtp.univ-angers.fr, serge.tahe@univ-angers.fr , serge.tahe@univ-angers.fr
From: serge.tahe@univ-angers.fr
To: serge.tahe@univ-angers.fr
Subject: test
ligne1
ligne2
ligne3
屏幕结果:
11.5. 客户端/服务器回显
我们创建了一个回显服务。服务器将客户端发送的所有文本行以大写形式返回。该服务可通过线程同时为多个客户端提供服务。
服务器程序 (inet_08)
注:
- 第 39 行:sys.argv 表示脚本的参数。此处,参数必须采用 script_name port 的形式。因此必须有两个参数。此时,sys.argv[0] 即为 script_name,sys.argv[1] 即为 port;
- 第 53 行:echo 服务器是 ThreadedTcpServer 类的实例。该类的构造函数需要两个参数:
- 参数 1:一个包含两个元素的元组 (主机, 端口),用于指定机器和服务器监听端口;
- 参数 2:负责处理客户端请求的类名称。
- 第 57 行:创建了一个线程(但尚未启动)。该线程将执行 TCP 服务器的 [serve_forever] 方法。该方法是一个循环,用于监听客户端连接。一旦检测到客户端连接,将创建一个 ThreadedTCPRequestHandler 类的实例。其 handle 方法负责与客户端进行通信;
- 第 59 行:回显服务线程启动。从此时起,客户端即可连接到该服务;
- 第 27 行:回显服务器类。它继承自两个类:
*SocketServer.ThreadingMixIn*和SocketServer.TCPServer。这使其成为一个多线程 TCP 服务器:服务器在一个线程中运行,而每个客户端则在另一个线程中得到服务; - 第 9 行:处理客户端请求的类。它继承自 SocketServer.StreamRequestHandler 类。因此,它继承了两个属性:
- rfile:用于读取客户端发送数据的读取流——可视为文本文件;
- wfile:用于向客户端发送数据的写入流——可视为文本文件。
- 第 11 行:handle 方法处理客户端请求;
- 第 13 行:执行此 handle 方法的线程;
- 第 17 行:用于处理客户端请求的循环。当客户端发送空行时,循环结束;
- 第 19 行:读取客户端请求;
- 第 21 行:self.client_address[0] 表示客户端的 IP 地址。cur_thread.getName() 是执行 handle 方法的线程名称;
- 第 23 行:对客户端的响应包含两个部分——服务该客户端的线程名称,以及客户端发送的命令(已转换为大写)。
客户端程序 (inet_06)
结果
服务器在命令窗口中启动:
在第二个窗口中启动第一个客户端:
客户端向服务器发送命令后,收到服务器返回的相同命令(大写形式)。在第三个窗口中启动第二个客户端:
此时服务器控制台显示如下:
客户端在不同的线程中得到正确处理。要停止一个客户端,只需输入一个空命令。
11.6. 通用 TCP 服务器
我们建议编写一个 Python 脚本,
- 将作为 TCP 服务器运行,能够同时服务一个客户端,
- 接收客户端发送的文本行,
- 并能接收来自键盘的文本行并将它们发送回客户端。
因此,键盘前的用户充当服务器:
- 他们在控制台上看到客户端发送的文本行;
- 并通过在键盘上输入回复来响应客户端。
因此,它能够适应任何类型的客户端。这就是为什么我们将它称为“通用 TCP 服务器”。这是一个用于探索 TCP 通信协议的实用工具。在下面的示例中,TCP 客户端将是一个 Web 浏览器,这将使我们能够探索 Web 客户端使用的 HTTP 协议。
![]() |
程序(inet_10)
注:
- 第 57 行:该 TCP 服务器将是 SocketServer.TCPServer 类的实例。其构造函数接受两个参数:
- 第一个参数是一个包含两个元素的元组 (主机, 端口),其中“主机”是服务运行的机器(通常为 localhost),而“端口”是服务用于等待(监听)客户端请求的端口;
- 第二个参数指定客户端的服务类。当客户端连接时,会创建该服务类的实例,其 handle 方法必须管理与客户端的连接。
Tcp SocketServer.TCPServer 并非多线程的。它每次只服务一个客户端;
- 第 59 行:执行 Tcp 服务器的
serve\_forever方法。这是一个无限循环,用于等待客户端; - 第 9 行:此处的 TCP 服务器是一个从 SocketServer.StreamRequestHandler 类派生的类。这使得与客户端交换的数据流可以被视为文本文件。我们之前已经遇到过这个类。我们拥有以下方法:
- *
readline*用于从客户端读取一行文本; write用于将文本行发回给客户端。
- *
- 第 12 行:
*self.client\_address[0]* 是客户端的 IP 地址; - 第 14 行:TCP 服务器将使用两个线程与客户端通信
- 一个线程用于从客户端读取行;
- 一个线程用于向客户端写入文本行。
- 第 14 行:创建用于从客户端读取行的线程。其
target参数指定了该线程执行的方法。该方法在第 25 行定义; - 第 25 行:启动读取线程;
- 第 25–32 行:读取线程执行的方法;
- 第 28 行:读取线程读取客户端发送的所有文本行,直到接收到“bye”这一行;
- 第 18 行:现在我们处于向客户端写入数据的线程中。其目的是将用户在键盘上输入的所有文本行发送给客户端。
结果
服务器
客户端浏览器
服务器接收到的请求
用户通过键盘输入的服务器响应(不含 --> 符号)
- 第1-5行:发送给客户端的HTTP响应;
- 第6行:向客户端发送HTML页面;
- 第7行:与客户端的对话结束。客户端服务将终止,连接将被关闭,这将突然中断正在读取客户端发送的文本行的线程;
- 发送给客户端的HTTP响应的第1–5行具有以下含义:
- 第1行:找到了客户端请求的资源;
- 第2行:服务器标识;
- 第 3 行:服务器将在发送资源后关闭连接;
- 第4行:服务器发送的资源类型:HTML文档;
- 第 5 行:空行。
浏览器显示的页面 [1]:
![]() |
如果查看浏览器接收到的源代码[2],我们会发现网页浏览器接收到的HTML代码确实就是我们发送给它的那个。




