在这之前先了解下什么是事件驱动编程

传统的编程是如下线性模式的:
开始--->代码块A--->代码块B--->代码块C--->代码块D--->......--->结束
每一个代码块里是完成各种各样事情的代码,但编程者知道代码块A,B,C,D...的执行顺序,唯一能够改变这个流程的是数据。输入不同的数据,根据条件语句判断,流程或许就改为A--->C--->E...--->结束。每一次程序运行顺序或许都不同,但它的控制流程是由输入数据和你编写的程序决定的。如果你知道这个程序当前的运行状态(包括输入数据和程序本身),那你就知道接下来甚至一直到结束它的运行流程。
对于事件驱动型程序模型,它的流程大致如下:
开始--->初始化--->等待
与上面传统编程模式不同,事件驱动程序在启动之后,就在那等待,等待什么呢?等待被事件触发。传统编程下也有“等待”的时候,比如在代码块D中,你定义了一个input(),需要用户输入数据。但这与下面的等待不同,传统编程的“等待”,比如input(),你作为程序编写者是知道或者强制用户输入某个东西的,或许是数字,或许是文件名称,如果用户输入错误,你还需要提醒他,并请他重新输入。事件驱动程序的等待则是完全不知道,也不强制用户输入或者干什么。只要某一事件发生,那程序就会做出相应的“反应”。这些事件包括:输入信息、鼠标、敲击键盘上某个键还有系统内部定时器触发。

Twsited异步网络框架

Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议、线程、数据库管理、网络操作、电子邮件等。

事件驱动

简而言之,事件驱动分为二个部分:第一,注册事件;第二,触发事件。

自定义事件驱动框架,命名为:“弑君者”:

#!/usr/bin/env python
# -*- coding:utf-8 -*- # event_drive.py 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')

程序员使用“弑君者框架”:

#!/usr/bin/env python
# -*- coding:utf-8 -*- 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实现了IProtocol接口,它包含如下的方法:

makeConnection               在transport对象和服务器之间建立一条连接
connectionMade 连接建立起来后调用
dataReceived 接收数据时调用
connectionLost 关闭连接时调用

Transports

Transports代表网络中两个通信结点之间的连接。Transports负责描述连接的细节,比如连接是面向流式的还是面向数据报的,流控以及可靠性。TCP、UDP和Unix套接字可作为transports的例子。它们被设计为“满足最小功能单元,同时具有最大程度的可复用性”,而且从协议实现中分离出来,这让许多协议可以采用相同类型的传输。Transports实现了ITransports接口,它包含如下的方法:

write                   以非阻塞的方式按顺序依次将数据写到物理连接上
writeSequence 将一个字符串列表写到物理连接上
loseConnection 将所有挂起的数据写入,然后关闭连接
getPeer 取得连接中对端的地址信息
getHost 取得连接中本端的地址信息

将transports从协议中分离出来也使得对这两个层次的测试变得更加简单。可以通过简单地写入一个字符串来模拟传输,用这种方式来检查。

EchoServer

from twisted.internet import protocol
from twisted.internet import reactor #reactor是twisted事件循环的核心,它提供了一些服务的基本接口,像网络通信、线程和事件的分发 class Echo(protocol.Protocol): #必须自己定义一个类,继承protocol,成为protocol的子类
def dataReceived(self, data): # 只要twisted收到数据就会调用此方法
self.transport.write(data) #写入数据到物理链接 类似send发送数据 def main():
factory = protocol.ServerFactory() #protocol.ServerFactor是一个基础工厂类,里面为空,但是你必须要定义,将你自定义的类作为参数传入
factory.protocol = Echo #定义类下的protocol变量的值,默认在ServerFactory里protocol字段值是None,在此将类的内存地址传入给protocol
reactor.listenTCP(1234,factory)#reactor绑定端口和传入protocol的值(类名),客户端连接过来的操作在自定义的类里完成
reactor.run() # 启动分发器 | 类似于select的监听,有连接就触发重新定义类里的操作 (因为在上面已经绑定了类) if __name__ == '__main__':
main()

EchoClient

#!/usr/bin/env python
# -*- coding:utf-8 -*-
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): #连接一建立成功,就会自动调用 此方法
print("connection is build, sending data...")
self.transport.write(bytes("hello alex!","utf8")) # 向server端send一条消息 def dataReceived(self, data): # 接受server端返回的消息
"As soon as any data is received, write it back."
print ("Server said:", data.decode())
self.transport.loseConnection()# 调用该方法,自动执行conectionLost方法
# exit('exit') def connectionLost(self, reason):
print ("====connection lost===") class EchoFactory(protocol.ClientFactory): # client也必须定义自己的类,继承ClientFactory类,重写方法
protocol = EchoClient #父类调用了protocol,但是在父类里protocol为空,类似于handle,所以你要在这里重新给protocol赋值(类的内存地址),客户端执行的操作在该这定义 def clientConnectionFailed(self, connector, reason): # 父类里的该方法为空,你必须自己定义 (如果连接失败了,直接执行该方法)
print ("Connection failed - goodbye!")
reactor.stop() def clientConnectionLost(self, connector, reason): # 同理(如果连接关闭了,执行该方法,类似于socketserver的finish)
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) #连接server,传入类
reactor.run() # this only runs if the module was *not* imported
if __name__ == '__main__':
main()

运行服务器端脚本将启动一个TCP服务器,监听端口1234上的连接。服务器采用的是Echo协议,数据经TCP transport对象写出。运行客户端脚本将对服务器发起一个TCP连接,回显服务器端的回应然后终止连接并停止reactor事件循环。这里的Factory用来对连接的双方生成protocol对象实例。两端的通信是异步的,connectTCP负责注册回调函数到reactor事件循环中,当socket上有数据可读时通知回调处理。

其实在这里也可以用上次socketclient的脚本来访问server,只不过twisted里实现了这种方法 ,上述是按照他规定的方法来完成交互。

一个传送文件的例子 

server side

#!/usr/bin/env python
# -*- coding:utf-8 -*-
#_*_coding:utf-8_*_
# This is the Twisted Fast Poetry Server, version 1.0 import optparse, os # optparse 类似于sys.argv 处理用户的输入的参数 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 twisted_sendfile.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)#设置参数,如果用户输入的是--port,规定必须为int
help = "The interface to listen on. Default is localhost."
parser.add_option('--iface', help=help, default='localhost')# 指定地址 默认localhost
options, args = parser.parse_args() # 解析用户输入的参数
print("--arg:",args) #解析用户除参数以为的字符串,这里为文件名
print("-->",options) #解析用户输入的参数,类型为字典--> {'iface': 'localhost', 'port': 123}
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): #handle
def connectionMade(self):
self.transport.write(self.factory.poem)
self.transport.loseConnection() class PoetryFactory(ServerFactory): #基础类
protocol = PoetryProtocol# 导入自定义的类,因为ServerFactory类里并没有做任何事情,所以我们只能亲历而为了
def __init__(self, poem):#因为基类无法添加形参,自定义一个构造方法,让用户传入文件内容
self.poem = poem def main():
options, poetry_file = parse_args()#options 用户传入的参数,poetry_file 文件名
poem = open(poetry_file).read() # 打开文件
factory = PoetryFactory(bytes(poem,"utf8")) # 初始化基类,传入读取的数据
from twisted.internet import reactor # 导入事件分发器
port = reactor.listenTCP(options.port or 9000, factory,
interface=options.iface) # 绑定端口,默认9000,interface 指定主机地址
print ('Serving %s on %s.' % (poetry_file, port.getHost()))
reactor.run() if __name__ == '__main__':
main()

client side

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# This is the Twisted Get Poetry Now! client, version 3.0. # NOTE: This should not be used as the basis for production code. 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() # _表示过滤掉第一个值
print('==addr:',_,addresses) #==addr: {} ['111', '222', '333']
if not addresses:# 如果没输入地址,打印help
print (parser.format_help())
parser.exit() def parse_address(addr):# 区分用户指定的主机和端口,默认为127.0.0.1
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 parse_address(addresses)
return map(parse_address, addresses)
class PoetryProtocol(Protocol): # handle
poem = ''
def dataReceived(self, data): # 接受数据
self.poem += data
#self.factory = PoetryClientFactory
print('[%s] recv:[%s]' %(self.transport.getPeer(),len(self.poem))) def connectionLost(self, reason): # 连接关闭后执行此函数
self.poemReceived(self.poem) def poemReceived(self, poem): #
self.factory.poem_finished(poem)
class PoetryClientFactory(ClientFactory):#定义基类继承指定的类
protocol = PoetryProtocol #绑定和server交互的类
def __init__(self, callback):
self.callback = callback
def poem_finished(self, poem):
self.callback(poem) #执行回调的那个函数
#self.get_poem(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) # 实例化ProtryClientFactory 将传入的回调函数传入
reactor.connectTCP(host, port, factory) # 链接
def poetry_main():
addresses = parse_args() #((172.0.0.1,9000),(...))
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) # 将got_poem函数链接函数
reactor.run() print("main loop done...")
#for poem in poems:
# Eprint poem if __name__ == '__main__':
poetry_main()

事件驱动之Twsited异步网络框架的更多相关文章

  1. Twsited异步网络框架

    Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. Twisted介绍:http://blog.csdn.net/hanhuili/a ...

  2. python2.0_s12_day10_Twsited异步网络框架

    Twsited异步网络框架 Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. Package application Configu ...

  3. Voovan 是一个高性能异步网络框架和 HTTP(Java)

    Voovan 是一个高性能异步网络框架和 HTTP 服务器框架,同时支持 HTTP 客户端抓取.动态编译支持.数据库访问封装以及 DateTime.String.Log.反射.对象工具.流操作.文件操 ...

  4. 协程,事件驱动,异步io模型,异步网络框架

    协程是一种用户态的轻量级线程,内核不知道它的存在.协程运行于一个线程中,协程的切换是由用户控制的.线程的切换是由cpu来控制的,而协程的切换是由用户控制的.协程的执行时串行的. select/poll ...

  5. uvloop —— 超级快的 Python 异步网络框架

    简短介绍 asyncio是遵循Python标准库的一个异步 I/O框架.在这篇文章里,我将介绍 uvloop: 可以完整替代asyncio事件循环.uvloop是用Cython写的,基于 libuv. ...

  6. 【从0到1】android网络框架的选型参考

    项目会使用到 socket tcp 级的网络访问,想选取一个使用较成熟异步网络框架, 提到的网络框架: 1. volley, 2. xutils. 3. android 4. netty, 5. mi ...

  7. 基于redis AE异步网络架构

    最近的研究已redis源代码,redis高效率是令人钦佩. 在我们的linux那个机器,cpu型号, Intel(R) Pentium(R) CPU G630 @ 2.70GHz  Intel(R) ...

  8. 对比Tornado和Twisted两种异步Python框架

    做Python的人,一定知道两个性能优秀的异步网络框架:tornado,和twisted. 那么,这两个著名的框架,又有什么异同呢?tornado和twisted,我都用在几个游戏项目中,做过后端,觉 ...

  9. Python twisted事件驱动网络框架 源码剖析

    一.Twisted简介 Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. 事件驱动简而言之,事件驱动分为二个部分:第一,注册事件:第 ...

随机推荐

  1. css 修改滚动条

    ::-webkit-scrollbar { width: 10px;}::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgb ...

  2. 字符串处理——(第一次作业Draw输入命令处理部分升级)

    #include<iostream> #include<sstream> //使用istringstream必须包含的头文件 #include<string> #i ...

  3. 关于阿里 阿里巴巴共享业务事业部UED团队 出品的sui基于zepto的开源UI框架的使用心得

    1.项目官网地址:http://m.sui.taobao.org/ 2.项目使用可以参考开始使用和示例 3.项目是放在 Github 上的 https://github.com/sdc-alibaba ...

  4. codeforces 724D(贪心)

    题目链接:http://codeforces.com/contest/724/problem/D 题意:给定一个字符串和一个数字m,选取一个一个子序列s,使得对于字符串中任意长度为m的子序列都至少含有 ...

  5. Day21_IO第三天

    1.IO体系总图 2.字符流体系图 记忆路线:输入输出流前面加File和Buffered,这就记住6个了,还剩两个转换流名字比较特殊,需要着重记一下(转换流:字节和字符的组合,所以起名字叫InputS ...

  6. 用.NET从外部dwg文件导入块

    翻译并引自Kean's blog的两篇文章: http://through-the-interface.typepad.com/through_the_interface/2006/08/import ...

  7. LintCode MinStack

    Implement a stack with min() function, which will return the smallest number in the stack. It should ...

  8. must implement the inherited abstract method

    The type VideoView must implement the inherited abstract method MediaController.MediaPlayerControl.g ...

  9. SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT 'OpenRowset/OpenDatasource' 的访问

    消息 15281,级别 16,状态 1,第 2 行SQL Server 阻止了对组件 'Ad Hoc Distributed Queries' 的 STATEMENT 'OpenRowset/Open ...

  10. 信号量 semaphore 和 @synchronized 的运用

    1. //创建全局队列 dispatch_queue_t queue = dispatch_get_global_queue(0, 0); //创建信号量 dispatch_semaphore_t s ...