socketserver编程—Python编程从入门到精通(8)

发表于:2018-12-27 11:19

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:叶维忠    来源:51Testing软件测试网原创

  17.3、socketserver编程
  Python语言提供了高级别的网络服务模块socketserver,在里面提供了服务器中心类,它可以简化网络服务器的开发步骤。本节将详细讲解使用socketserver对象实现网络编程的知识。
  17.3.1、socketserver模块基础
  socketserver是Python标准库中的一个高级模块,在Python 3以前的版本中命名为socketServer,推出socketserver的目的是简化程序代码。
  在Python程序中,虽然使用前面介绍的socket模块可以创建服务器,但是开发者要对网络连接等进行管理和编程。为了更加方便地创建网络服务器,在Python标准库中提供了一个创建网络服务器的模块socketserver。socketserver框架将处理请求划分为两部分,分别对应服务器类和请求处理类。服务器类处理通信问题,请求处理类处理数据交换或传送问题。这样,更加容易进行网络编程和程序的扩展。同时,该模块还支持快速的多线程或多进程的服务器编程。
  在socketserver模块中使用的服务器类主要有TCPServer、UDPServer、ThreadingTCPServer、ThreadingUDPServer、ForkingTCPServer、ForkingUDPServer等。其中有TCP字符的就是使用TCP协议的服务器类,有UDP字符的就是使用UDP协议的服务器类,有Threading字符的是多线程服务器类,有Forking字符的是多进程服务器类。要创建不同类型的服务器程序,只须继承其中之一或直接实例化,然后调用服务器类方法serve_forever()即可。
  在socketserver模块中包含了如表17-5所示的类。
  其中有TCP字符使用的是TCP协议的服务器类,UDP字符使用的是UDP协议的服务器类,Threading字符使用的是多线程服务器类,Forking字符使用的是多进程服务器类。要想创建不同类型的服务器程序,只须继承其中之一或直接实例化,然后调用服务器类方法serve_forever()即可。这些服务器的构造方法参数主要有以下两个。
  "server_address:由IP地址和端口构成的元组。
  "RequestHandlerClass:处理器类,供服务器类调用处理数据。
  在socketserver模块中最为常用的处理器类主要有StreamRequestHandler(基于TCP协议)和DatagramRequestHandler(基于UDP协议)。只要继承其中之一,就可以自定义一个处理器类。通过覆盖以下3个方法可以实现自定义功能。
  "setup():为请求准备请求处理器(请求处理的初始化工作)。
  "handle ():实现具体的请求处理工作(解析请求、处理数据、发出响应)。
  "finish():清理请求处理器的相关数据。
  17.3.2、使用socketserver创建TCP"客户端/服务器"连接
  下面的实例代码演示了socketserver建立TCP"客户端/服务器"连接的过程。
  实例17-3 创建可靠的、相互通信的"客户端/服务器"连接
  源码路径 daima\17\17-3
  实例文件ser.py的功能是使用socketserver模块创建基于TCP协议的服务器端程序,它能够将接收到的信息直接发回到客户端。文件ser.py的具体实现代码如下所示。
#定义类StreamRequestHandler的子类MyTcpHandler
class MyTcpHandler(socketserver. StreamRequest Handler):
def handle(self):     #定义函数handle()
while True:
data = self.request.recv(1024)
#返回接收到的数据
if not data:
Server.shutdown()#关闭连接
break            #停止循环
print('接收信息:',data.decode
('utf-8')) #显示接收信息
self.request.send(data) #发送信息
return
#定义类TCPServer的对象实例
Server = socketserver.TCPServer((HOST,PORT),MyTcpHandler)
Server.serve_forever()          #循环并等待其停止
  在上述实例代码中,首先自定义了一个继承自StreamRequestHandler的处理器类,并覆盖了方法handler()以实现数据处理。然后直接实例化了类TCPServer,调用方法serve_forever()启动服务器。执行效果如图17-5所示。
  
  图17-5  执行效果
  17.4、HTTP协议开发
  在计算机网络模型中,套接字编程属于底层网络协议开发的内容。虽然说编写网络程序需要从底层开始构建,但是自行处理相关协议是一件比较麻烦的事情。其实对于大多数程序员来说,最常见的网络编程开发是针对应用协议进行的。在Python程序中,使用内置的包urllib和http可以完成HTTP协议层程序的开发工作。本节将详细讲解使用包urllib和包http开发HTTP应用程序的过程。
  17.4.1、使用urllib包
  在Python程序中,urllib包主要用于处理URL(Uniform Resource Locator,统一资源定位符)操作,使用urllib操作URL可以像使用和打开本地文件一样操作,非常简单而又易上手。在包urllib中主要包括如下所示的模块。
  "urllib.request:用于打开URL网址。
  "urllib.error:用于定义常见的urllib.request会引发的异常。
  "urllib.parse:用于解析URL。
  "urllib.robotparser:用于解析robots.txt文件。
  在包urllib中主要包括如下所示的方法。
  (1)方法urlopen()。
  在urllib.request模块中,方法urlopen()的功能是打开一个URL地址,其语法格式如下所示。
urlopen (url, data, proxies)
  "url:表示要进行操作的URL地址。
  "data:用于向URL传递的数据,是一个可选参数。
  "proxies:表示使用的代理地址,可选参数。
  方法urlopen()将返回一个HTTPResponse实例(类文件对象),可以像操作文件一样使用read()、readline()和close()等方法对URL进行操作。
  方法urlopen()能够打开url所指向的URL。如果没有给定协议或者下载方案(Scheme),或者传入了"file"方案,urlopen()会打开一个本地文件。
  对于所有的 HTTP 请求来说,常见的请求类型是"GET"。在这些情况中,向Web 服务器发送的请求字符串(编码过的键值对,如urlencode()函数返回的字符串)应该是url 的一部分。如果使用"POST"请求方法,请求的字符串(编码过的)应该放到postQueryData 变量中。一旦连接成功,函数urlopen()将会返回一个文件类型对象,就像在目标路径下打开了一个可读文件。例如,如果文件对象是f,那么"句柄"会支持一些读取内容的方法,例如f.read()、f.readline()、f.readlines()、f.close()和f.fileno()。另外,方法f.info()可以返回MIME(Multipurpose Internet Mail Extension,多用途因特网邮件扩充)头文件。这个头文件通知浏览器返回的文件类型,以及可以用哪类应用程序打开。
  例如,浏览器本身可以查看HTML、纯文本文件,渲染PNG(Portable Network Graphics)文件、JPEG(Joint Photographic Experts Group)或者GIF(Graphics Interchange Format)文件。而其他如多媒体或特殊类型文件需要通过其他应用程序才能打开。最后,方法geturl()在考虑了所有可能发生的重定向后,从最终打开的文件中获得真实的URL。在下面列出了urllib.urlopen()文件类型对象的常用方法。
  "f.read([bytes]):从f中读出所有或bytes 个字节。
  "f.readline():从f中读取一行。
  "f.readlines():从f中读出所有行,作为列表返回。
  "f.close():关闭f的URL 连接。
  "f.fileno():返回f的文件句柄。
  "f.info():获得f的MIME 头文件。
  "f.geturl():返回f的真正URL。
  注意:因为从Python 2.6 版本开始,在urllib中弃用urlopen()方法。而在Python 3.0版本中移除了这个函数,在3.x 版本中需要使用urllib.request.urlopen()方法。
  (2)方法urlretrieve()。
  使用urllib.request模块中的方法urlretrieve()可以将URL另存为本地文件。此方法的语法格式如下所示。
urlretrieve(url, filename, reporthook, data)
  "url:要保存的URL地址。
  "filename:指定保存的文件名,可选参数。
  "reporthook:回调函数,可选参数。
  "data:发送的数据,一般用于POST,可选参数。
  除了像 urlopen()函数这样从URL中读取内容外,函数urlretrieve()可以方便地将url中的整个HTML文件下载到本地硬盘上。下载后的数据可以另存为一个localfile或者一个临时文件。如果该文件已经复制到本地或者URL指向的文件就是本地文件,就不会发生后面的下载操作。如果提供了reporthook,则在每块数据下载或传输完成后会调用这个函数。在调用时会使用3个参数:目前读入的块数、块的字节数和文件的总字节数。如果正在用文本或图表向用户显示"下载状态"信息,这个函数将会非常有用。函数urlretrieve()返回一个二元组(filename, mime_ hdrs)。其中filename表示含有下载数据的本地文件名,mime_hdrs表示Web 服务器响应后返回的一系列MIME 文件头。对本地文件来说,mime_hdrs是空的。
  (3)方法urlencode()。
  在urllib.parse模块中,方法urlencode()的功能是对URL进行编码。此方法的语法格式如下所示。
urlencode (query, doseq)
  "query:要进行编码的变量和值组成的字典;
  "doseq:可选参数,如果为True则将元组的值分别编码成"变量=值"的形式。
  在Python程序中,函数urlencode()的功能是接收字典的键值对,并将其编译成字符串,作为CGI 请求的URL 字符串的一部分。键值对的格式是"键=值",以连接符(&)划分。另外,键及其对应的值会传到quote_plus()函数中进行适当的编码。
  (4)方法quote()和方法quote_plus()。
  在urllib.parse模块中,方法quote()和方法quote_plus()的功能是替换字符串中的特殊字符,使其符合URL要求使用的字符。在Python程序中,函数quote()用来获取URL 数据,并将其编码,使其可以用于URL 字符串中。在现实应用中必须对某些不能打印的或者不被Web 服务器作为有效URL 接收的特殊字符串进行转换。这就是quote()函数的功能。这两个方法的语法格式如下所示。
quote (string, safe='/')
quote_plus (string, safe='')
  "string:要进行替换的字符串。
  "safe:可选参数,设置不需要替换的字符。
  在Python程序中,逗号、下划线、句号、斜线和字母数字这类符号不需要转化,其他的则均需要转换。另外,在那些URL 不能使用的字符前边会添加上百分号(%),同时把它们转换成十六进制格式,例如,"%xx",其中,"xx"表示这个字符的ASCII码的十六进制值。当调用quote*()时,字符串转换成一个可在URL 字符串中使用的等价字符串。safe 字符串可以包含一系列不能转换的字符,默认字符是斜线"/"。
  (5)方法unquote()和方法unquote_plus()。
  在Python程序中,unquote()方法与quote()方法的功能完全相反,前者将所有编码为"%xx"式的字符转换成等价的ASCII 码值。在urllib.parse模块中,使用方法unquote()和方法unquote_plus()可以将使用quote()方法和quote_plus()方法替换后的字符还原(在Python 2.x中直接由urllib模块进行处理)。方法unquote()和方法unquote_plus()的语法格式如下所示。
unquote(string)
unquote_plus (string)
  其中,参数"string"表示要进行还原的字符串。
  下面的实例代码演示了使用urlopen()方法在百度搜索关键词中得到第一页链接的过程。
  实例17-4 显示关键词"www.toppr.net"在百度中的链接
  源码路径 daima\17\17-4
  实例文件url.py的具体实现代码如下所示。
from urllib.request import urlopen
#导入Python的内置模块
from urllib.parse import urlencode
#导入Python的内置模块
import re                #导入Python的内置模块
##wd = input('输入一个要搜索的关键字:')
wd= 'www.toppr.net'      #初始化变量wd
wd = urlencode({'wd':wd})#对URL进行编码
url = 'http://www.baidu.com/s?' + wd#初始化url变量
page = urlopen(url).read()#打开变量url的网页并读取内容
#定义变量content,对网页进行编码处理,并实现特殊字符处理
content = (page.decode('utf-8')).replace
("\n","").replace("\t","")
title = re.findall(r'<h3 class="t".*?h3>', content)
#正则表达式处理
title = [item[item.find('href =')+6:item.find('target=')] for item in title] #正则表达式处理
title = [item.replace(' ','').replace('"','') for item in title] #正则表达式处理
for item in title:       #遍历title
print(item)           #显示遍历值
  在上述实例代码中,使用方法urlencode()对搜索的关键字"www.toppr.net"进行URL编码。在拼接到百度的网址后,使用urlopen()方法发出访问请求并取得结果。最后通过将结果进行解码和正则搜索与字符串处理后输出。执行效果如图17-6所示。
  
  17.4.2、使用HTTP包
  在Python程序中,包HTTP实现了对HTTP协议的封装。在HTTP包中,主要包含如下所示的模块。
  "http.client:底层的HTTP协议客户端,可以为urllib.request模块所用。
  "http.server:提供了基于socketserver模块的基本HTTP服务器类。
  "http.cookies:cookie的管理工具。
  "http.cookiejar:提供了cookie的持久化支持。
  在http.client模块中,主要包括如下3个用于客户端的类。
  "HTTPConnection:基于HTTP协议访问的客户端。
  "HTTPSConnection:基于HTTPS协议访问的客户端。
  "HTTPResponse:基于HTTP协议的服务端回应。
  下面的实例代码演示了使用http.client.HTTPConnection对象访问网站的过程。
  实例17-5 使用HTTPConnection对象访问网站
  源码路径 daima\17\17-5
  实例文件fang.py的具体实现代码如下所示。
from http.client import HTTPConnection #导入内置模块
mc = HTTPConnection('www.baidu.com:80')
#基于HTTP协议访问的客户端
mc.request('GET','/')        #设置GET请求方法
res = mc.getresponse()       #获取访问的网页
print(res.status,res.reason) #输出响应的状态
print(res.read().decode('utf-8')) #显示获取的内容
  在上述实例代码中只是实现了一个基本的访问实例,首先实例化http.client.HTTPConnection对指定请求的方法为GET,然后使用getresponse()方法获取访问的网页,并输出响应的状态。执行效果如图17-7所示。
  
相关阅读:
21/212>
《2023软件测试行业现状调查报告》独家发布~

精彩评论

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号