600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > python 网络编程----非阻塞或异步编程

python 网络编程----非阻塞或异步编程

时间:2022-03-03 21:08:27

相关推荐

python 网络编程----非阻塞或异步编程

From:/uid-20730371-id-765038.html

非阻塞或异步编程

例如,对于一个聊天室来说,因为有多个连接需要同时被处理,所以很显然,阻塞或同步的方法是不合适的,这就像买票只开了一个窗口,佷多人排队等一样。那么我们如何解决这个问题呢?主要有三种方法:forking、threading、异步I/O。

Forking和threading的方法非常简单,通过使用SocketServer服务类的min-in类就可以实现。forking只适用于类Unix平台;threading需要注意内存共享的问题。

异步I/O如果底层的方法来实现是有点困难的。要简单点,我们可以考虑使用标准库中的框架或Twisted(Twisted是一个非常强大的异步网络编程的框架)。

一、用ScoketServer实现Forking和threading

下面我们使用两个例子来分别创建forking服务器和threading服务器。

Forking服务器:

fromSocketServerimportTCPServer,ForkingMixIn,StreamRequestHandler

classServer(ForkingMixIn,TCPServer):pass

classHandler(StreamRequestHandler):

defhandle(self):

addr=self.request.getpeername()

print'Gotconnectionfrom',addr

self.wfile.write('Thankyouforconnecting')

server=Server(('',1234),Handler)

server.serve_forever()

threading服务器:

fromSocketServerimportTCPServer,ThreadingMixIn,StreamRequestHandler

classServer(ThreadingMixIn,TCPServer):pass

classHandler(StreamRequestHandler):

defhandle(self):

addr=self.request.getpeername()

print'Gotconnectionfrom',addr

self.wfile.write('Thankyouforconnecting')

server=Server(('',1234),Handler)

server.serve_forever()

二、使用select实现异步I/O

所谓异步I/O,打个比方,就是如果一大群人都想你听他说话,那么你就给他们每人一分钟的时间说,大家轮流说,没说完的待会儿轮到时再继续说。也就是一个时间片的方法。

要实现异步I/O,我们可以通过使用框架asyncore/asynchat或Twisted,它们都是基于select函数或poll函数(poll只适于类Unix系统)的。select和poll函数都来自select模块。

select 函数要求三个必须序列作为参数和一个可选的以秒为单位的超时值。序列中是表示文件描述符的整数值,它们是我们要等待的连接。这三个序列是关于输入、输出和 异常条件的。如果超时值没有给出的话,select将处于阻塞状态(也就是等待)直到有文件描述符准备动作。如果超时值给出了,那么select只阻塞给 定的时间。如果超时值是0的话,那么将不阻塞。select返回的值是一个由三个序列组成的元组,它们分别代表相应参数的活动的子集。例如,第一个序列返 回的是用于读的输入文件描述符构成的序列。

序列可以包含文件对象(不适于Windows)或socket。下面这个例子创建一个使用 select去服务几个连接的服务器(注意:服务端的socket自身也提供给了select,以便于它能够在有新的连接准备接受时发出信号通知)。这个 服务器只是简单地打印接受自客户端的数据。你可以使用telnet(或写一个基于socket的简单的客户端)来连接测试它。

selectserver

importsocket,select

s=socket.socket()

host=socket.gethostname()

port=1234

s.bind((host,port))

s.listen(5)

inputs=[s]

whileTrue:

rs,ws,es=select.select(inputs,[],[])

forrinrs:

ifriss:

c,addr=s.accept()

print'Gotconnectionfrom',addr

inputs.append(c)

else:

try:

data=r.recv(1024)

disconnected=notdata

exceptsocket.error:

disconnected=True

ifdisconnected:

printr.getpeername(),'disconnected'

inputs.remove(r)

else:

printdata

三、Twisted

Twisted 是针对Python的一个事件驱动的网络框架,最初是为了网络游戏而开发的,但是现在被应用于各类网络软件。用Twisted,你可以实现事件处理器,非 常类似用GUI工具包(Tk,GTK,Qt,wxWidgets)。这部分我将介绍一些基本的概念和演示如何使用Twisted来做一些相对简单的 网络编程。Twisted是非常强大的框架并提供了大量的支持,如:Web服务器和客户端、 SSH2,SMTP,POP3,IMAP4,AIM,ICQ,IRC,MSN,Jabber,NNTP,DNS等等。

早先我们所写的基于socket的服务器,它们都有一个显示的事件循环:寻找新的连接和新的数据;基于SocketServer的服务器有一个隐含的循环:寻找连接和为连接创建处理器。但时处理器仍然时显示的读数据。

而 Twisted使用了更多的基于事件的方式。要写一个基本的服务器,你要实现事件处理器,它处理诸如一个新的客户端连接、新的数据到达和客户端连接中断等 情况。在Twisted中,你的事件处理器定义在一个protocol中;你也需要一个factory,当一个新的连接到达时它能够构造这个 protocol对象,但是如果你仅仅想创建一个自定义的Protocol类的实例的话,你可以使用来自Twisted的factory,Factory 类在模块twisted.internet.protocol中。当你写你的protocol时,使用 twisted.internet.protocol模块中的Protocol作为你的父类。当你得到一个连接时,事件处理器 connectionMade被调用;当你丢失了一个连接时,connectionLost被调用。从客户端接受数据使用处理器 dataReceived。但是你不能使用事件处理策略向客户端发送数据;要向客户端发送数据,你可以使用self.transport,它有一个 write方法。它也有一个client属性,其中包含了客户端的地址(主机名和端口)。

下面这个例子是一个Twisted版的服务器。 其中实例化了Factory并设置了它的protocol属性以便它知道使用哪个protocol与客户端通信(这就是所谓的你的自定义 protocol)。然后你使用factory开始监听指定的端口,factory通过实例化的protocol对象处理连接。监听使用reactor模 块中的listenTCP函数。最后,你通过调用reactor模块中的run函数来开始服务器。

fromtwisted.internetimportreactor

fromtwisted.internet.protocolimportProtocol,Factory

#定义你Protocol类

classSimpleLogger(Protocol):

defconnectionMade(self):

print'Gotconnectionfrom',self.transport.client

defconnectionLost(self,reason):

printself.transport.client,'disconnected'

defdataReceived(self,data):

printdata

#实例化Factory

factory=Factory()

#设置factory的protocol属性以便它知道使用哪个protocol与客户端通信(这就是所谓的你的自定义

#protocol)

factory.protocol=SimpleLogger

#监听指定的端口

reactor.listenTCP(1234,factory)

#开始运行主程序

reactor.run()

为 你的处理目的而写一个自定义的protocol是很容易的。模块twisted.protocols.basic中包含了几个有用的已存在的 protocol,其中的LineReceiver执行dataReceived并在接受到了一个完整的行时调用事件处理器lineReceived。如 果当你在接受数据时除了使用lineReceived,还要做些别的,那么你可以使用LineReceiver定义的名为rawDataReceived 事件处理器。下面是一使用LineReceiver的服务器例子:

fromtwisted.internetimportreactor

fromtwisted.internet.protocolimportFactory

fromtwisted.protocols.basicimportLineReceiver

classSimpleLogger(LineReceiver):

defconnectionMade(self):

print'Gotconnectionfrom',self.transport.client

defconnectionLost(self,reason):

printself.transport.client,'disconnected'

deflineReceived(self,line):

printline

factory=Factory()

factory.protocol=SimpleLogger

reactor.listenTCP(1234,factory)

reactor.run()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。