news 2026/2/8 2:17:06

【Python 教程14】- 网络编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Python 教程14】- 网络编程

14、Python 教程 - 网络编程

本章首先概述​Python 标准库中的一些网络模块​。然后​讨论 SocketServer 和相关的类​,并介绍​同时处理多个连接的各种方法​。最后,简单地说一说​Twisted​,这是一个使用 Python 编写网络程序的框架,功能丰富而成熟。

几个网络模块

模块 socket

网络编程中的一个基本组件是套接字(socket)。套接字基本上是一个信息通道,两端各有一个程序。套接字分为两类:服务器套接字和客户端套接字。
为传输数据,套接字提供了两个方法:send 和 recv(表示 receive)。要发送数据,可调用方法 send 并提供一个字符串;要接收数据,可调用 recv 并指定最多接收多少个字节的数据。
最简单的服务器服务器套接字先调用方法 bind,再调用方法 listen 来监听特定的地址。然后,客户端套接字就可连接到服务器了,办法是调用方法 connect 并提供调用方法 bind 时指定的地址(在服务器端,可使用函数 socket.gethostname 获取当前机器的主机名)。这里的地址是一个格式为(host, port)的元组,其中 host 是主机名(如 www.example.com),而 port 是端口号(一个整数)。方法 listen 接受一个参数——待办任务清单的长度(即最多可有多少个连接在队列中等待接纳,到达这个数量后将开始拒绝连接)服务器套接字开始监听后,就可接受客户端连接了,这是使用方法 accept 来完成的。这个方法将阻断(等待)到客户端连接到来为止,然后返回一个格式为(client, address)的元组,其中 client 是一个客户端套接字,而 address 是前面解释过的地址。服务器能以其认为合适的方式处理客户端连接,然后再次调用 accept 以接着等待新连接到来。这通常是在一个无限循环中完成的。

import socket s = socket.socket() host = socket.gethostname() port = 1234 s.bind((host,port)) s.listen(5) while True: c,addr = s.accept() print('Got connection from',addr) c.send('Thank you for connecting') c.close()

最简单的客户端

import socket s = socket.socket() host = socket.gethostname() port = 1234 s.connect((host,port)) print(s.recv(1024))

模块 urllib 和 urllib2

1,打开远程文件

from urllib.request import urlopen import re webpage = urlopen('https://beyondyanyu.blog.csdn.net')#变量webpage将包含一个类似于文件的对象,这个对象与该网站相关联 text = webpage.read() m = re.search(b'<a href="([^"]+)".*?>about</a>',text,re.IGNORECASE) m.group(1)

2,获取远程文件函数urlopen返回一个类似于文件的对象,可从中读取数据。可使用urlretrieve,下载文件,并将其副本存储在一个本地文件中。这个函数不返回一个类似于文件的对象,而返回一个格式为(filename, headers)的元组,其中 filename 是本地文件的名称(由 urllib 自动创建),而 headers 包含一些有关远程文件的信息。调用函数urlcleanup且不提供任何参数,清空所有临时文件。
获取 CSDN 的主页,并将其存储到文件 C:\webpage.html 中。

urlretrieve('https://beyondyanyu.blog.csdn.net', 'C:\\python_webpage.html')

一些实用的函数

函数名称描述
quote(string[, safe])返回一个字符串,其中所有的特殊字符(在 URL 中有特殊意义的字符)都已替换为对 URL 友好的版本(如将~替换为 %7E)参数 safe 是一个字符串(默认为’/’),包含不应像这样对其进行编码的字符。
quote_plus(string[, safe])类似于 quote,但也将空格替换为加号。
unquote(string)与 quote 相反。
unquote_plus(string)与 quote_plus 相反。
urlencode(query[, doseq])将映射(如字典)或由包含两个元素的元组(形如(key,value))组成的序列转换为“使用 URL 编码的”字符串。

其他模块

模块描述
asynchat包含补充 asyncore 的功能
asyncore异步套接字处理程序
cgi基本的 CGI 支持
CookieCookie 对象操作,主要用于服务器
cookielib客户端 Cookie 支持
email电子邮件(包括 MIME)支持
ftplibFTP 客户端模块
gopherlibGopher 客户端模块
httplibHTTP 客户端模块
imaplibIMAP4 客户端模块
mailbox读取多种邮箱格式
mailcap通过 mailcap 文件访问 MIME 配置
mhlib访问 MH 邮箱
nntplibNNTP 客户端模块
poplibPOP 客户端模块
robotparser解析 Web 服务器 robot 文件
SimpleXMLRPCServer一个简单的 XML-RPC 服务器
smtpdSMTP 服务器模块
smtplibSMTP 客户端模块
telnetlibTelnet 客户端模块
urlparse用于解读 URL
xmlrpclibXML-RPC 客户端支持

SocketServer 及相关的类

模块SocketServer是标准库提供的服务器框架的基石,这个框架包括 BaseHTTPServer、SimpleHTTPServer、CGIHTTPServer、SimpleXMLRPCServer 和 DocXMLRPCServer 等服务器,它们在基本服务器的基础上添加了各种功能。
SocketServer 包含 4 个基本的服务器:TCPServer(支持 TCP 套接字流)、UDPServer(支持 UDP 数据报套接字)以及更难懂的 UnixStreamServer 和 UnixDatagramServer。后面 3 个你可能不会用到。
使用模块 SocketServer 编写服务器时,大部分代码都位于请求处理器中。基本请求处理程序类 BaseRequestHandler 将所有操作都放在一个方法中——服务器调用的方法 handle。这个方法可通过属性 self.request 来访问客户端套接字。如果处理的是流(使用 TCPServer 时很可能如此),可使用 StreamRequestHandler 类,它包含另外两个属性:self.rfile(用于读取)和 self.wfile(用于写入)。
基于 SocketServer 的极简服务器

from socketserver import TCPServer,StreamRequestHandler class Handler(StreamRequestHandler): def handle(self): addr = self.request.getpeername() print('Got connection from',addr) self.wfile.write('Thank you for connecting') server = TCPServer(('',1234),Handler) server.serve_forever()

多个连接

处理多个连接的主要方式有三种:​分叉​(forking)、线程化和​异步 I/O​。分叉占用的资源较多,且在客户端很多时可伸缩性不佳。
进程:运行着的程序****分叉:对进程(运行的程序)进行分叉时,基本上是复制它,而这样得到的两个进程都将从当前位置开始继续往下执行,且每个进程都有自己的内存副本(变量等)。原来的进程为父进程,复制的进程为子进程。查看函数 fork 的返回值可以区别父子进程。
在分叉服务器中,对于每个客户端连接,都将通过分叉创建一个子进程。父进程继续监听新连接,而子进程负责处理客户端请求。客户端请求结束后,子进程直接退出。由于分叉出来的进程并行地运行,因此客户端无需等待。
鉴于分叉占用的资源较多(每个分叉出来的进程都必须有自己的内存),还有另一种解决方案:​线程化​。
线程是轻量级进程(子进程),都位于同一个进程中并共享内存。这减少了占用的资源,但也带来了一个缺点:由于线程共享内存,你必须确保它们不会彼此干扰或同时修改同一项数据,否则将引起混乱。这些问题都属于同步问题。
种避免线程和分叉的办法是使用​Stackless Python​。它是一个能够快速而轻松地在不同上下文之间切换的 Python 版本。它支持一种类似于线程的并行方式,名为​微线程​,其可伸缩性比真正的线程高得多。

使用 SocketServer 实现分叉和线程化

仅当方法 handle 需要很长时间才能执行完毕时,分叉和线程化才能提供帮助。请注意,​Windows 不支持分叉​。
分叉服务器

from socketserver import TCPSercer,ForkingMixIn,StreamRequestHandler class Server(ForkingMixIn,TCPSercer):pass class Handler(StreamRequestHandler): def handle(self): addr = self.request.getpeername() print('Got connection from',addr) self.wfile.write('Thank you for connecting') server = Server(('',1234),Handler) server.serve_forever()

线程化服务器

from socketserver import TCPServer, ThreadingMixIn, StreamRequestHandler class Server(ThreadingMixIn, TCPServer): pass class Handler(StreamRequestHandler): def handle(self): addr = self.request.getpeername() print('Got connection from', addr) self.wfile.write('Thank you for connecting') server = Server(('', 1234), Handler) server.serve_forever()

使用 select 和 poll 实现异步 I/O

当服务器与客户端通信时,来自客户端的数据可能时断时续。如果使用了分叉和线程化,这就不是问题:因为一个进程(线程)等待数据时,其他进程(线程)可继续处理其客户端。然而,另一种做法是只处理当前正在通信的客户端。你甚至无需不断监听,只需监听后将客户端加入队列即可。这就是框架 asyncore/asynchat 和 Twisted 采取的方法。这种功能的基石是函数 select 或 poll)。这两个函数都位于模块 select 中,其中 poll 的可伸缩性更高,但只有 UNIX 系统支持它(Windows 不支持)。
使用 select 的简单服务器函数 select 接受三个必不可少的参数和一个可选参数,其中前三个参数为序列,而第四个参数为超时时间(单位为秒)。这三个序列分别表示需要输入和输出以及发生异常(错误等)的连接。如果没有指定超时时间,select 将阻断(即等待)到有文件描述符准备就绪;如果指定了超时时间,select 将最多阻断指定的秒数;如果超时时间为零,select 将不断轮询(即不阻断)。
select 返回三个序列(即一个长度为 3 的元组),其中每个序列都包含相应参数中处于活动状态的文件描述符。

import socket,select s = socket.socket() host = socket.gethostname() port = 1234 s.bind((host,port)) s.listen(5) inputs = [s] while True: rs,ws,es = select.select(inputs,[],[]) for r in rs: if r is s: c,addr = s.accept() print('Got connection from',addr) inputs.append(c) else: try: data = r.recv(1024) disconnected = not data except socket.error: disconnected = True if disconnected: print(r.getpeername(),'disconnected') inputs.remove(r) else: print(data)

select 模块中的轮询事件常量

事件名描述
POLLIN文件描述符中有需要读取的数据
POLLPRI文件描述符中有需要读取的紧急数据
POLLOUT文件描述符为写入数据做好了准备
POLLERR文件描述符出现了错误状态
POLLHUP挂起。连接已断开。
POLLNVAL无效请求。连接未打开
使用 poll 的简单服务器方法 poll 使用起来比 select 容易。调用 poll 时,将返回一个轮询对象。使用方法 register 向这个对象注册文件描述符(或包含方法 fileno 的对象)。注册后可使用方法 unregister 将它们删除。注册对象(如套接字)后,可调用其方法 poll(它接受一个可选的超时时间参数)。这将返回一个包含(fd, event)元组的列表(可能为空),其中 fd 为文件描述符,而 event 是发生的事件。event 是一个位掩码,这意味着它是一个整数,其各个位对应于不同的事件。
import socket,select s = socket.socket() host = socket.gethostname() port = 1234 s.bind((host,port)) fdmap = { s.fileno():s} s.listen(5) p = select.poll() p.register(s) while True: events = p.poll() for fd, event in events: if fd in fdmap: c, addr = s.accept() print('Got connection from', addr) p.register(c) fdmap[c.fileno()] = c elif event & select.POLLIN: data = fdmap[fd].recv(1024) if not data: 没有数据 --连接已关闭 print(fdmap[fd].getpeername(), 'disconnected') p.unregister(fd) del fdmap[fd] else: print(data)

Twisted

Twisted 是由 Twisted Matrix Laboratories(http://twistedmatrix.com)开发的,这是一个事件驱动的 Python 网络框架。
使用 Twisted 创建的简单服务器事件处理程序是在协议中定义的。你还需要一个工厂,它能够在新连接到来时创建这样的协议对象。如果你只想创建自定义协议类的实例,可使用 Twisted 自带的工厂——模块twisted.internet.protocol中 的Factory类。编写自定义协议时,将模块twisted.internet.protocol中的 Protocol 作为超类。有新连接到来时,将调用事件处理程序 connectionMade;连接中断时,将调用 connectionLost。来自客户端的数据是通过处理程序 dataReceived 接收的。

from twisted.internet import reactor from twisted.internet.protocol import Protocol, Factory class SimpleLogger(Protocol): def connectionMade(self): print('Got connection from', self.transport.client) def connectionLost(self, reason): print(self.transport.client, 'disconnected') def dataReceived(self, data): print(data) factory = Factory() factory.protocol = SimpleLogger reactor.listenTCP(1234, factory) reactor.run()

使用协议 LineReceiver 改进后的日志服务器如果使用 telnet 连接到这个服务器以便测试它,每行输出可能只有一个字符,是否如此取决于缓冲等因素。为此,可编写一个自定义协议。模块 twisted.protocols.basic 包含几个预定义的协议,其中一个就是 LineReceiver。它实现了 dataReceived,并在每收到一整行后调用事件处理程序 lineReceived。

from twisted.internet import reactor from twisted.internet.protocol import Factory from twisted.protocols.basic import LineReceiver class SimpleLogger(LineReceiver): def connectionMade(self): print('Got connection from', self.transport.client) def connectionLost(self, reason): print(self.transport.client, 'disconnected') def lineReceived(self, line): print(line) factory = Factory() factory.protocol = SimpleLogger reactor.listenTCP(1234, factory) reactor.run()

小结

概念描述
套接字和模块 socket套接字是让程序(进程)能够通信的信息通道,这种通信可能需要通过网络进行。模块 socket 让你能够在较低的层面访问客户端套接字和服务器套接字。服务器套接字在指定的地址处监听客户端连接,而客户端套接字直接连接到服务器。
urllib 和 urllib2这些模块让你能够从各种服务器读取和下载数据,为此你只需提供指向数据源的 URL 即可。模块 urllib 是一种比较简单的实现,而 urllib2 功能强大、可扩展性极强。这两个模块都通过诸如 urlopen 等函数来完成工作。
框架 SocketServer这个框架位于标准库中,包含一系列同步服务器基类,让你能够轻松地编写服务器。它还支持使用 CGI 的简单 Web(HTTP)服务器。如果要同时处理多个连接,必须使用支持分叉或线程化的混合类。
select 和 poll这两个函数让你能够在一组连接中找出为读取和写入准备就绪的连接。这意味着你能够以循环的方式依次为多个连接提供服务,从而营造出同时处理多个连接的假象。另外,相比于线程化或分叉,虽然使用这两个函数编写的代码要复杂些,但解决方案的可伸缩性和效率要高得多。
Twisted这是 Twisted Matrix Laboratories 开发的一个框架,功能丰富而复杂,支持大多数主要的网络协议。虽然这个框架很大且其中使用的一些成例看起来宛如天书,但其基本用法简单而直观。框架 Twisted 也是异步的,因此效率和可伸缩性都非常高。对很多自定义网络应用程序来说,使用 Twisted 来开发很可能是最佳的选择。

本章介绍的新函数

函数描述
urllib.urlopen(url[, data[, proxies]])根据指定的 URL 打开一个类似于文件的对象
urllib.urlretrieve(url[,fname[,hook[,data]]])下载 URL 指定的文件
urllib.quote(string[, safe])替换特殊的 URL 字符
urllib.quote_plus(string[, safe])与 quote 一样,但也将空格替换为 +
urllib.unquote(string)与 quote 相反
urllib.unquote_plus(string)与 quote_plus 相反
urllib.urlencode(query[, doseq])对映射进行编码,以便用于 CGI 查询中
select.select(iseq, oseq, eseq[, timeout])找出为读/写做好了准备的套接字
select.poll()创建一个轮询对象,用于轮询套接字
reactor.listenTCP(port, factory)监听连接的 Twisted 函数
reactor.run()启动主服务器循环的 Twisted 函数
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/6 14:46:06

Calibre(开源电子书管理软件)

Calibre 是一款开源的电子书管理软件&#xff0c;它支持多种电子书格式&#xff0c;具备格式转换、元数据编辑、电子书阅读等功能&#xff0c;还能与几乎所有电子书阅读器兼容&#xff0c;方便用户管理和使用自己的电子书资源。 软件功能 电子书转换&#xff1a;Calibre 可以将…

作者头像 李华
网站建设 2026/2/6 14:40:34

Excel批量处理身份证信息太麻烦?这个免费工具让我效率翻倍

作为一名HR,每次整理员工档案都让我头疼不已。上周公司新入职了80多人,领导要求我从身份证号中提取出生日期、性别、年龄等信息,建立完整的员工信息表。 看着Excel里密密麻麻的身份证号,我陷入了沉思… 传统方法有多折磨人? 以前处理这类需求,我通常有两种选择: 方法一:手动输…

作者头像 李华
网站建设 2026/2/7 21:40:39

把火关在该待的地方:防火分隔设施安装的底线工程

一、什么是防火分隔设施安装&#xff1f;防火分隔设施安装&#xff0c;是指在建筑和工业项目中&#xff0c;依据国家消防技术规范和建筑防火设计要求&#xff0c;对防火墙、防火门、防火卷帘、防火隔墙、防火封堵等设施进行安装、固定、调试和验收的系统性工程。防火分隔设施并…

作者头像 李华
网站建设 2026/2/6 14:36:53

java+vue基于springboot的社区团购系统

目录基于SpringBoot和Vue的社区团购系统摘要系统核心功能模块技术实现亮点应用价值开发技术源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;基于SpringBoot和Vue的社区团购系统摘要 社区团购系统是一种结合线上订购与线下配送的电商模式…

作者头像 李华
网站建设 2026/2/6 14:36:50

java+vue基于springboot的社区流浪动物领养管理系统

目录系统概述技术栈核心功能系统优势开发技术源码文档获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;系统概述 基于SpringBoot和Vue的社区流浪动物领养管理系统旨在通过数字化手段优化流浪动物救助与领养流程。系统采用前后端分离架构&#xf…

作者头像 李华
网站建设 2026/2/8 6:54:49

TDD 原则:测试驱动开发核心准则与实践要点

TDD 原则&#xff1a;测试驱动开发核心准则与实践要点 TDD&#xff08;Test-Driven Development&#xff0c;测试驱动开发&#xff09;是一种先写测试用例&#xff0c;再编写业务代码的软件开发方法论&#xff0c;核心是通过「测试→编码→重构」的循环&#xff0c;让测试用例…

作者头像 李华