Twsited异步网络框架
Twsited
Twsited是一个事件驱动的网络架构,其中包含了很多功能,例如:网络协议,线程,数据库管理,网络操作,电子邮件等。
事件驱动
简单来说,事件驱动分为两个部分,第一注册事件,第二触发事件
例子:
event_list = [] def run(): for event in event_list: obj = event() obj.execute() class BaseHandler(object): """ 用户必须继承该类,从而规范所有类的方法(类似于接口的功能) """ def execute(self): raise Exception('you must overwrite execute')
程序使用这个架构
from source import event_drive class MyHandler(event_drive.BaseHandler): def execute(self): print 'event-drive execute MyHandler' event_drive.event_list.append(MyHandler) event_drive.run()
# 简单理解就是别人写好的框架,你在使用的时候必需遵守它们的约定。
Protocols
Protocols描述了如何以异步的方式处理网络中的事件。HTTP,DNS以及IMAP是应用层协议中的列子
Protocols的方法:
makeConnection 在transport对象中服务器之间建立一条连接
connectionMade 连接建立起来后调用
dataReceived 接收数据时调用
connectionLost 关闭连接时调用
Transports
Transports代表网络中两个通信节点之间的连接,Transports负责描述连接的细节,比如连接是面向流式的还是面向数据包的,流控以及可靠。TCP,UDP和Unix套接字可作为Transports的例子。它们被设计为“满足最小功能单元,同时具有最大控制的可复用性”,而且从协议实现中分离出来,这让许多协议可以采用相同类型的传输。
所包含的方法:
write 以非阻塞的方式按顺序依次将数据写到物理连接上
writeSequence 将一个字符串列表写到物理连接上
loseConnecton 将所有挂起的数据写入,然后关闭连接
getPeer 取得连接中对端的地址信息
getHost 取得连接中本端的地址信息
将Transports从协议中分离出来也使得对这两个层次的测试变的更加简单。可以通过简单的写入一个字符串来模拟传输,用这种方式检查。
EchoServer
from twisted.internet import protocol from twisted.internet import reactor class Echo(protocol.Protocol): def dataReceived(self, data): self.transport.write(data) def main(): factory = protocol.ServerFactory() factory.protocol = Echo reactor.listenTCP(1234,factory) reactor.run() if __name__ == '__main__': main()
from twisted.internet import reactor, protocol # a client protocol class EchoClient(protocol.Protocol): """Once connected, send a message, then print the result.""" def connectionMade(self): self.transport.write("hello alex!") def dataReceived(self, data): "As soon as any data is received, write it back." print "Server said:", data self.transport.loseConnection() def connectionLost(self, reason): print "connection lost" class EchoFactory(protocol.ClientFactory): protocol = EchoClient def clientConnectionFailed(self, connector, reason): print "Connection failed - goodbye!" reactor.stop() def clientConnectionLost(self, connector, reason): print "Connection lost - goodbye!" reactor.stop() # this connects the protocol to a server running on port 8000 def main(): f = EchoFactory() reactor.connectTCP("localhost", 1234, f) reactor.run() # this only runs if the module was *not* imported if __name__ == '__main__': main()
运行服务器端脚本将启动一个TCP服务器,监听端口1234上的连接。服务器采用的是Echo协议,数据经TCP Transports对象写出。运行客户脚本将对服务器发起一个TCP连接,回显服务器端的回应然后终止连接并停止reactor事件循环。这里的Factory用来对连接的方法生成Protocol对象实例。两端的通信是异步的,connectTCP负责注册回调函数到reactor事件循环中,当socket上有数据可读时通知回调处理。
一个传送文件的例子
server side
import optparse, os from twisted.internet.protocol import ServerFactory, Protocol def parse_args(): usage = """usage: %prog [options] poetry-file This is the Fast Poetry Server, Twisted edition. Run it like this: python fastpoetry.py <path-to-poetry-file> If you are in the base directory of the twisted-intro package, you could run it like this: python twisted-server-1/fastpoetry.py poetry/ecstasy.txt to serve up John Donne's Ecstasy, which I know you want to do. """ parser = optparse.OptionParser(usage) help = "The port to listen on. Default to a random available port." parser.add_option('--port', type='int', help=help) help = "The interface to listen on. Default is localhost." parser.add_option('--iface', help=help, default='localhost') options, args = parser.parse_args() print("--arg:",options,args) if len(args) != 1: parser.error('Provide exactly one poetry file.') poetry_file = args[0] if not os.path.exists(args[0]): parser.error('No such file: %s' % poetry_file) return options, poetry_file class PoetryProtocol(Protocol): def connectionMade(self): self.transport.write(self.factory.poem) self.transport.loseConnection() class PoetryFactory(ServerFactory): protocol = PoetryProtocol def __init__(self, poem): self.poem = poem def main(): options, poetry_file = parse_args() poem = open(poetry_file).read() factory = PoetryFactory(poem) from twisted.internet import reactor port = reactor.listenTCP(options.port or 9000, factory, interface=options.iface) print 'Serving %s on %s.' % (poetry_file, port.getHost()) reactor.run() if __name__ == '__main__': main()
client side
import optparse from twisted.internet.protocol import Protocol, ClientFactory def parse_args(): usage = """usage: %prog [options] [hostname]:port ... This is the Get Poetry Now! client, Twisted version 3.0 Run it like this: python get-poetry-1.py port1 port2 port3 ... """ parser = optparse.OptionParser(usage) _, addresses = parser.parse_args() if not addresses: print parser.format_help() parser.exit() def parse_address(addr): if ':' not in addr: host = '127.0.0.1' port = addr else: host, port = addr.split(':', 1) if not port.isdigit(): parser.error('Ports must be integers.') return host, int(port) return map(parse_address, addresses) class PoetryProtocol(Protocol): poem = '' def dataReceived(self, data): self.poem += data def connectionLost(self, reason): self.poemReceived(self.poem) def poemReceived(self, poem): self.factory.poem_finished(poem) class PoetryClientFactory(ClientFactory): protocol = PoetryProtocol def __init__(self, callback): self.callback = callback def poem_finished(self, poem): self.callback(poem) def get_poetry(host, port, callback): """ Download a poem from the given host and port and invoke callback(poem) when the poem is complete. """ from twisted.internet import reactor factory = PoetryClientFactory(callback) reactor.connectTCP(host, port, factory) def poetry_main(): addresses = parse_args() from twisted.internet import reactor poems = [] def got_poem(poem): poems.append(poem) if len(poems) == len(addresses): reactor.stop() for address in addresses: host, port = address get_poetry(host, port, got_poem) reactor.run() for poem in poems: print poem if __name__ == '__main__': poetry_main()
Twisted深入
http://krondo.com/an-introduction-to-asynchronous-programming-and-twisted/
http://blog.csdn.net/hanhuili/article/details/9389433