IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 系统运维 -> Python基础教程(第2版)第十四章 网络编程 -> 正文阅读

[系统运维]Python基础教程(第2版)第十四章 网络编程

1.网络设计模块

1.1 socket模块

套接字(socket)主要是两个程序之间的“信息通道”,程序可能(通过网络连接)分布在不同的计算机上通过套接字相互发送信息

一个套接字就是一个socket模块中的socket类的实例,它的实例化需要3个参数

????????第1个参数是地址族(默认是socket.AF_ INET)

????????第2个参数是流 (socket.SOCK_STREAM,默认值)或数据报(socket.SOCK_DGRAM)套接字

????????第3个参数是使用的协议(默认是0,使用默认值即可)

????????对于一个普通的套接字,不需要提供任何参数

1.1.1 服务器套接字(同步网络编程)

????????服务器必须准备随时处理客户端的连接,同时还要处理多个连接

????????创建一个服务器套接字后,让它等待连接,它就会在某个网络地址 (IP地址和端口号的组合)处监听

????????服务器端套接字使用bind方法后,再调用listen方法去监听给定的地址

????????????????地址:一个格式为(host, port)的元组,host是主机名, port是端口号(一个整数)

????????????????listen方法只有一个参数:服务器未处理的连接的长度(即允许排队等待的连接数目,这些连接在停止接收之前等待接收)

????????服务器端套接字开始监听后,它就可以接受客户端的连接,这个步骤使用accept方法来完成

????????????????accept方法会阻塞(等待)直到客户端连接,然后该方法就返回一个格式为 (client, address)的元组,client是一个客户端套接字,address是一个前面解释过的地址

????????????????服务器能处理客户端到它满意的程度,然后调用另一个accept方法开始等待下一个连接

1.1.2 客户端套接字

????????处理客户端套接字通常比处理服务器端套接字容易,因为客户机只是简单地连接,完成事务,断开连接

????????客户端套接字使用connect方法连接到服务器(connect方法中的地址与bind中的地址相同)

1.1.3 套接字方法

send:使用字符串参数调用send以发送数据

revc:使用一个所需的(最大)字节数做参数调用recv来接收数据,如果不能确定使用哪个数
字比较好,那么1024是个很好的选择

#一个小型服务器
import socket
s=socket.socket()
host=socket.gethostname()
port=1234

s.bind((host,port))	#服务器(host,port)
s.listen(5)	#监听给定的地址(允许排队等待的连接数目: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))	#连接到服务器(host,port)
print(s.recv(1024))	#接收数据(最大字节数:1024)

能在服务器还在运行时运行多个客户机,通过用服务器端所在机器的实际主机名来代替客户端调用gethostname所得到的主机名,就可以让两个运行在不同机器上的程序通过网络连接起来

1.2 urllib和urllib2模块

通过一个简单的函数调用,几乎可以把任何URL指向的东西用做程序的输人,即能通过网络访问文件,就像那些文件存在于你的电脑上一样

如果只使用简单的下载,urllib就足够了

? ? ? ? 使用urllib模块的urlopen,可以像打开本地文件一样打开远程文件,不同的是可以使用只读模式(也可以以file开头的URL访问本地文件)

????????urlopen返回的是一个能从中读取数据的类文件对象,该对象支持close、read、readline、readlines和迭代

from urllib import urlopen
webpage = urlopen('http://www.python.org')
page = urlopen('file:C:\\text\\somefile.txt')

????????如果想提取前面打开的Python页中“ About”链接的 (相对)URL,可以用正则表达式实现?

import re
text=webpage.read()
m=re.search('<a href="([^"]+)" .*?>about</a>',text,re.IGNORECASE)	#如果网页内容发生变化,则需要自行修改正则表达式
print(m.group(1))

如果希望urllib为你下载文件并在本地文件中存储一个文件的副本,那么可以使用urlretrieve

????????urlretrieve返回一个元组 (filename,headers)而不是类文件对象,filename是本地文件的名宇(由urllib自动创建),headers包含一些远程文件的信息

????????如果想要为下载的副本指定文件名,可以在urlretrieve函数的第2个参数中给出

urlretrieve('http://www.python.org','C:\\python_webpage.html')

????????如果没有指定文件名,文件就会放在临时的位置,用open函数可以打开它,但如果完成了对它的操作,就可以删除它以节省硬盘空间

????????要清理临时文件,可以调用urlcleanup函数,但不要提供参数,该函数会负责清理工作

如果需要使用HTTP验证 (HTTP authentication) 或cookie或者要为自己的协议写扩展程序
话,那么urllib2是个好的选择

1.3其他模块

2.SocketSever和它的朋友们

SocketServer模块是标准库中很多服务器框架的基础,这些服务器框架都为基础服务器增加了特定的功能

????????BaseHTTTPServer、SimpleHTTPServer、 CGIHTTPServer、SimpleXMLRPCServer、
DocXMLRPCServer

SocketServer包含了4个基本的类:针对 TCP套接字流的TCPServer,针对UDP数据报套接字
的UDPServer,以及针对性不强的UnixStreamServer 和UnixDatagramServer

写一个使用SocketServer框架的服务器时,大部分代码会在一个请求处理程序中

????????每当服务器收到一个来自客户端的请求时,就会实例化一个请求处理程序,此时它的各种处理方法会在处理请求时被调用,具体调用哪个方法取决于特定的服务器和使用的处理程序类

????????这样可以把它们子类化,使得服务器调用自定义的处理程序集

????????基本的BaseRequestHandler类把所有的操作都放到了处理器的一个叫做handle的方法中,这个方法会被服务器调用,这个方法就会访问属性self.request中的客户端套接字(如果使用的是流,那么可以使用StreamRequestHandler类,这个类创建了两个新属性:self.rfile用于读取和self. wfile用于写入),然后就能使用这些类文件对象和客户机进行通信

SocketServer框架中的其他类实现了对HTTP服务器的基本支持,其中包括运行CGI脚本,包括对XML RPC(在第27章讨论)的支持

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()

????????StreamRequestHandler在连接处理完后会负责关闭连接?

3.多连接

目前为止讨论的服务器解决方案都是同步的:即一次只能连接一个客户机并处理它的请求。如果每个请求只是花费很少的时间,比如一个完整的聊天会话,那么同时能处理多个连接就很重要

有三种主要的方法能实现这个目的:分叉(forking)、线程(threading)以及异步I/O

通过对SocketServer服务器使用mix-in类,派生进程和线程很容易处理。即使要自己实现它们,这些方法也很容易使用

????????同时,它们也有缺点:分叉会占据资源,并且如果有太多的客户端时分叉不能很好分叉

????????尽管如此,对于合理数量的客户端,分叉在现代的UNIX或者Linux系统中是很高效的,如果有一个多CPU系统,那效率会更高

3.1 使用SocketSever进行分叉和线程处理

分叉是一个UNIX术语,当分叉一个进程(一个运行的程序)时,基本上是复制了它,并且分叉后的两个进程都从当前的执行点继续运行,每个进程都有自己的内存副本 (比如变量)

????????原来的进程称为父进程,复制的进程称为子进程

????????在一个使用分叉的服务器中,每一个客户端连接都利用分叉创造一个子进程

????????父进程继续监听新的连接,子进程处理客户端,当客户端的请求结束时,子进程就退出了

????????分叉的进程是并行运行的,客户端之间不必互相等待

#使用了分叉技术的服务器
from SocketServer import TCPServer,ForkingMixIn,StreamRequestHandler
class Server(ForkingMixIn,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=TCPServer(('',1234),Handler)
server.serve_forever()

因为分叉有点耗费资源(每个分叉出来的进程都需要自己的内存),这就存在了另一个选择:线程

????????线程是轻量级的进程或子进程,所有的线程都存在于相同的(真正的)进程中,共享内存? ? ?

?????????资源消耗的下降伴随着一个缺陷:因为线程共享内存,所以必须确保它们的变量不会冲突,或者是在同一时间修改同一内容,这会造成混乱,这些问题都可以归结为同步问题

在现代操作系统中(除了Windows,它不支持分叉),分叉实际是很快的,现代的硬件能比以往更好地处理资源消耗,如果不想被同步问题所困扰,分叉是一个很好的选择

#使用了线程处理的服务器
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=TCPServer(('',1234),Handler)
server.serve_forever()

避免线程和分叉的另外一种方法是转换到Stackless Python,一个为了能够在不同的上下文之间快速、方便切换而设计的Python版本

????????它支持一个叫做微线程(microthreads)的类线程的并行形式,微线程比真线程的伸缩性要好

3.2 带有select和poll的异步I/O

异步I/O在底层的实现有点难度,基本的机制是select模块的select函数

? ? ? ? 还存在更高的层次处理异步I/O的框架,这为处理一个强大可伸缩的机制提供了一个简单的、抽象的接口

????????包含在标准库中的这种类型的基本框架由asyncore和asynchat模块组成

????????Twisted是一个非常强大的异步网络编程框架

当一个服务器与一个客户端通信时,来自客户端的数据可能是不连续的,我们可以只处理在给定时间内真正要进行通信的客户端:不需要一直监听,只要监听一会,然后把它放在其他客户端的后面

上述功能的基础是来自select模块的select函数poll函数(poll的伸缩性更好,但它只能在UNIX系统中使用)

3.2.1?select函数

select函数需要3个序列(文件描述符整数)作为它的必选参数,此外还有一个可选的以秒为单位的超时时间作为第4个参数

? ? ? ? 3个序列用于输入、输出以及异常情况

?????????序列能包含文件对象(在Windows中行不通)或者套接字

????????如果没有给定超时时间,select会处于等待状态,直到其中的一个文件描述符已经为行动做好了准备

????????如果给定了超时时间,select最多阻塞给定的超时时间,如果给定的超时时间是0,那么就给出一个连续的poll

????????select的返回值是3个序列(也就是一个长度为3的元组),每个代表相应参数的一个活动子集,如返回的第1个序列是一个输入文件描述符的序列,其中有一些可以读取的东西

#使用了select的简单服务器
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)

3.2.2 poll函数?

poll方法使用起来比select简单,在调用poll时,会得到一个poll对象

????????可以使用poll对象的register方法注册一个文件描述符(或者是带有fileno方法的对象)

????????注册后可以使用unregister方法移除注册的对象

????????注册了一些对象(比如套接字)以后,就可以调用poll方法(带有一个可选的超时时间参数)并得到一个(fd,event)格式列表(可能是空的)

????????fd是文件描述符

????????event会告诉你发生了什么,它是一个位掩码(整数),这个整数的每个位对应不同的事件,那些不同的事件是select模块的常量,为了验证一个给定的事件是否发生了,可以使用按位与操作符(&):if event & select.POLLIN : ...????????

?

#使用poll的简单服务器
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)

4.Twisted

来自于Twisted Matrix实验室的Twisted是一个事件驱动的Python网络框架,原来是为网络游戏开发的,现在被所有类型的网络软件使用

在Twisted中,需要实现事件处理程序,事件处理程序在一个协议中定义,在一个新的连接到达时,同样需要一个创建这种协议对像的工厂

但如果只是想要创建一个通用的协议类的实例,那么就可以使用Twited自带的工厂(factory类在twisted.internet.protocol模块中)

当编写自己的协议时,要使用和超类一样的模块中的protocol

????????得到了一个连接后,事件处理程序connectionMade就会被调用

????????丢失了一个连接后,connectionLost就会被调用

????????来自客户端的数据是通过处理程序dataReceived接收的

? ? ? ? 如果想要使用事件处理策略来把数据发回到客户端,可以使用对象self.transport,这个对象有一个write方法,也有一个包含客户机地址(主机名和端口号)的client属性

#使用Twisted的简单服务器
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()

twisted.protoccls.basic模块中包含一个有用的预定义协议LineReceiver,它实现了dataReceived 并且只要收到了一整行就调用事件处理程序lineReceived

如果要在接受数据时做些事情,可以使用由LineReceiver定义的叫做rawDataReceived的事件处理程序,也可以使用lineReceived

#使用了LineReceiver协议改进的记录服务器
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 dataReceived(self,line):
		print(line)
factory=Factory()
factory.protocol=SimpleLogger
reactor.listenTCP(1234, factory)
reactor.run()

  系统运维 最新文章
配置小型公司网络WLAN基本业务(AC通过三层
如何在交付运维过程中建立风险底线意识,提
快速传输大文件,怎么通过网络传大文件给对
从游戏服务端角度分析移动同步(状态同步)
MySQL使用MyCat实现分库分表
如何用DWDM射频光纤技术实现200公里外的站点
国内顺畅下载k8s.gcr.io的镜像
自动化测试appium
ctfshow ssrf
Linux操作系统学习之实用指令(Centos7/8均
上一篇文章      下一篇文章      查看所有文章
加:2022-01-30 19:17:57  更:2022-01-30 19:20:22 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 7:53:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码