Twisted随笔
学习了socket后决定尝试使用框架,目标锁定了Twisted。
什么是Twisted?
twisted是一个用python语言写的事件驱动的网络框架,他支持很多种协议,包括UDP,TCP,TLS和其他应用层协议,比如HTTP,SMTP,NNTM,IRC,XMPP/Jabber。 非常好的一点是twisted实现和很多应用层的协议,开发人员可以直接只用这些协议的实现。其实要修改Twisted的SSH服务器端实现非常简单。很多时候,开发人员需要实现protocol类。
一个Twisted程序由reactor发起的主循环和一些回调函数组成。当事件发生了,比如一个client连接到了server,这时候服务器端的事件会被触发执行。
基于事件:
事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。另外两种常见的编程范式是(单线程)同步以及多线程编程。
来比较和对比一下单线程、多线程以及事件驱动编程模型。图21.1展示了随着时间的推移,这三种模式下程序所做的工作。这个程序有3个任务需要完成,每个任务都在等待I/O操作时阻塞自身。阻塞在I/O操作上所花费的时间已经用灰色框标示出来了。
在单线程同步模型中,任务按照顺序执行。如果某个任务因为I/O而阻塞,其他所有的任务都必须等待,直到它完成之后它们才能依次执行。这种明确的执行顺序和串行化处理的行为是很容易推断得出的。如果任务之间并没有互相依赖的关系,但仍然需要互相等待的话这就使得程序不必要的降低了运行速度。
在多线程版本中,这3个任务分别在独立的线程中执行。这些线程由操作系统来管理,在多处理器系统上可以并行处理,或者在单处理器系统上交错执行。这使得当某个线程阻塞在某个资源的同时其他线程得以继续执行。与完成类似功能的同步程序相比,这种方式更有效率,但程序员必须写代码来保护共享资源,防止其被多个线程同时访问。多线程程序更加难以推断,因为这类程序不得不通过线程同步机制如锁、可重入函数、线程局部存储或者其他机制来处理线程安全问题,如果实现不当就会导致出现微妙且令人痛不欲生的bug。
在事件驱动版本的程序中,3个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。事件驱动型程序比多线程程序更容易推断出行为,因为程序员不需要关心线程安全问题
体现在代码中,在定义协议时,事件方法会在相应事件发生时被调用,比如在接收新的连接或丢失连接时:
def connectionMade(self): #在得到连接时触发
self.transport.write('ftp-server: welcome to ftp!') #输出信息到客户端
print 'Got connection from ',self.transport.client def connectionLost(self, reason): #在失去连接时触发
print self.transport.client,'disconnect'
当有数据需要被接收时,dataReceived方法被调用:
def dataReceived(self,data)
print data
如果想实现只接收了一整行就调用事件处理方法可以使用lineReceived方法。注意,之后每接收一行都会调用一次事件方法...
def lineReceived(self, line):
print line
异步:
Twisted 官方称,“Twisted is event-based, asynchronous framework ”。这个“异步”功能的代表就是 deferred
deferred 的作用类似于“多线程”,负责保障多头连接、多项任务的异步执行。
但deferred “异步”功能的实现,与多线程完全不同,具有以下特点:
1. deferred 产生的 event,是函数调用返回的对象;
2. deferred 代表一个连接任务,负责报告任务执行的延迟情况和最终结果;
3. 对deferred 的操作,通过预定的“事件响应器”(event handler)进行。
有了deferred,即可对任务的执行进行管理控制。防止程序的运行,由于等待某项任务的完成而陷入阻塞停滞,提高整体运行的效率。
defered貌似有很多实现方式,我只学会了下面这种
def upload(self,path,content): #定义一个根据客户端请求写文件的方法,写完后生成一个hash码用于验证
with open(path,'wb') as f:
f.write(content)
with open(path,'rb') as f: #hmac验证
h = hmac.new('liqixuan')
h.update(f.read())
file_hash = h.hexdigest()
print(file_hash)
self.sendLine(file_hash) d = threads.deferToThread(self.upload,'D:/client_new.py',s) #生成defered对象,异步调用写文件方法
d.addCallbacks(self.finash,self.failed)
刚接触框架,还一头雾水,继续学习中,贴上一个练手代码:
功能:异地上传文件,文件异步传输,通过hash码验证文件的完整性
server:
#!/usr/bin/env python
#-*- coding:utf-8 -
from twisted.internet import reactor
from twisted.internet.protocol import Protocol,Factory
from twisted.protocols.basic import LineOnlyReceiver
import os,hmac
from twisted.internet import defer,threads '''
定义一个协议类,在一个新的连接到达时,创建这个协议对象的factory。
此协议类继承LineOnlyReceiver,在得到连接时触发connectionMade方法,
失去连接时触发connectionLost方法,接收数据时会每接收一行就触发一次lineReceived方法。
使用defered异步处理文件I/O
'''
class MyTwisted(Protocol): d def connectionMade(self): #在得到连接时触发
self.transport.write('ftp-server: welcome to ftp!') #输出信息到客户端
self.path = '' #初始化一些字段
self.li = []
self.begin = False
self.end = False
print 'Got connection from ',self.transport.client def connectionLost(self, reason): #在失去连接时触发
print self.transport.client,'disconnect' def finash(self,arg): #定义两个回调方法,对应执行成功和失败
print 'Finashed!' def failed(self,arg):
print 'Failed' def upload(self,path,content): #定义一个根据客户端请求写文件的方法,写完后生成一个hash码用于验证
with open(path,'wb') as f:
f.write(content)
with open(path,'rb') as f: #hmac验证
h = hmac.new('liqixuan')
h.update(f.read())
file_hash = h.hexdigest()
print(file_hash)
self.sendLine(file_hash) def lineReceived(self, line):
'''
由于每接收一行就会调用该方法,故每次需要对传输内容进行判断
''' #接收客户端发送的上传文件路径
if line.startswith('path_filename'):
self.path = line.replace('path_filename','')
if os.path.isdir(line):
self.sendLine('True') #反馈客户端
else:
self.sendLine('False') #反馈客户端 '''
开始接收文件内容时触发的事件
'''
if line.startswith('*begin*'): #设置一个文件开始位,标志开始传输文件内容
self.begin = True
line = line.replace('*begin*','') if '*end*' in line and '*begin*' not in line: #结束位
self.end = True
line = line.replace('*end*','') if self.begin: #为结束前将文件内容写进某个字段
self.li.append('%s\r\n' % line) if self.end: #收到结束标志后开始准备传输文件
self.begin = False #重置标志位
self.end = False
s = ''.join(self.li[:-1]) #去掉最后换行符 d = threads.deferToThread(self.upload,'D:/client_new.py',s) #生成defered对象,异步调用写文件方法
d.addCallbacks(self.finash,self.failed) #执行完毕后回调相应方法 factory = Factory()
factory.protocol = MyTwisted reactor.listenTCP(8000,factory)
reactor.run()
client:
#-*- coding:utf-8 -*-
import socket,os,hmac def upload():
local_path = raw_input('本地文件: ').strip()
if os.path.isfile(local_path):
upload_path = raw_input('文件上传路径: ').strip()
file_name = os.path.basename(local_path) sk.send('path_filename%s%s\r\n' % (upload_path,file_name)) #发送目标路径及文件名 answer = sk.recv(1024) #接收反馈,若路径不存在退出
if answer == 'False':
print('No such file or directory')
return
else:
print('ready to upload...') with open(local_path,'rb')as f: #若存在读文件
s = f.read()
s = '*begin*%s*end*\r\n' % s #添加首尾标志位并发送服务器
sk.send(s)
file_hash = sk.recv(1024) #接收反馈的hash码
file_hash = file_hash.replace('\r\n','')
print("target file's HASH is ",file_hash)
with open(local_path,'rb') as f: #得到原文件hash码
h = hmac.new('liqixuan')
h.update(f.read())
hash1 = h.hexdigest()
print("local file's HASH is",hash1)
if hash1 == file_hash: #若一致则上传成功
print 'file upload successful!'
else:
print 'file upload failed!' ip_port = ('127.0.0.1',8000)
sk = socket.socket()
sk.connect(ip_port)
server_data = sk.recv(1024)
print(server_data)
upload()
Twisted随笔的更多相关文章
- AI人工智能系列随笔
初探 AI人工智能系列随笔:syntaxnet 初探(1)
- 【置顶】CoreCLR系列随笔
CoreCLR配置系列 在Windows上编译和调试CoreCLR GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔 ...
- C++随笔:.NET CoreCLR之GC探索(4)
今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...
- C++随笔:从Hello World 探秘CoreCLR的内部(1)
紧接着上次的问题,上次的问题其实很简单,就是HelloWorld.exe运行失败,而本文的目的,就是成功调试HelloWorld这个控制台应用程序. 通过我的寻找,其实是一个名为TryRun的文件出了 ...
- ASP.NET MVC 系列随笔汇总[未完待续……]
ASP.NET MVC 系列随笔汇总[未完待续……] 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的. 学前篇之: ASP.NET MVC学前篇之扩展方法.链式编程 ASP. ...
- Mina、Netty、Twisted一起学(八):HTTP服务器
HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...
- 使用Beautiful Soup编写一个爬虫 系列随笔汇总
这几篇博文只是为了记录学习Beautiful Soup的过程,不仅方便自己以后查看,也许能帮到同样在学习这个技术的朋友.通过学习Beautiful Soup基础知识 完成了一个简单的爬虫服务:从all ...
- 利用Python进行数据分析 基础系列随笔汇总
一共 15 篇随笔,主要是为了记录数据分析过程中的一些小 demo,分享给其他需要的网友,更为了方便以后自己查看,15 篇随笔,每篇内容基本都是以一句说明加一段代码的方式, 保持简单小巧,看起来也清晰 ...
- 《高性能javascript》 领悟随笔之-------DOM编程篇(二)
<高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...
随机推荐
- JavaMail发送邮件第一版
首先,我们先来了解一个基本的知识点,用什么工具来发邮件? 简单的说一下,目前用的比较多的客户端:OutLook,Foxmail等 顺便了解一下POP3.SMTP协议的区别: POP3,全名为" ...
- Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结
Atitit.软件架构高扩展性and兼容性原理与概论实践attilax总结 1. 什么是可扩展的应用程序?1 2. 松耦合(ioc)2 3. 接口的思考 2 4. 单一用途&模块化,小粒度化2 ...
- 几句话就能让你理解:this、闭包、原型链
以下是个人对这三个老大难的总结(最近一直在学习原生JS,翻了不少书,不少文档,虽然还是新手,但我会继续坚持走我自己的路) 原型链 所有对象都是基于Object.prototype,Object.pro ...
- Dynamics CRM 2011-RootComponent Type
笔者因为时不时要导出solution,对solution xml进行处理,所以把xml中的rootcomponent type列一下 Type Description 1 Entity 2 Attr ...
- Android开发aidl使用中linkToDeath和unlinkToDeath的使用
1.Binder死亡代理 这一节首先将介绍Binder类中比较重要的两个方法linkToDeath和unlinkToDeath.我们知道Binder是运行在服务进程,若服务端进程因为某种原因“ ...
- nginx启动、关闭、重启
1.启动 [root@localhost local]# nginx/sbin/nginx #启动 [root@localhost local]# nginx/sbin/nginx -t #检查配置文 ...
- 【译】Spring 4 @Profile注解示例
前言 译文链接:http://websystique.com/spring/spring-profile-example/ 本文将探索Spring中的@Profile注解,可以实现不同环境(开发.测试 ...
- 如何升级PowerShell
背景: 开发的PowerShell 脚本需要使用Invoke-RestMethod命令,发现在老的服务器上不支持这一命令,经过查询得知由于PS版本的问题.涉及到了PS的升级,需要介绍下PowerShe ...
- Linux shell脚本编程(三)
Linux shell脚本编程 流程控制: 循环语句:for,while,until while循环: while CONDITION; do 循环体 done 进入条件:当CONDITION为“真” ...
- laravel框架中容器类简化代码-摘自某书
<?php //容器类装实例或提供实例的回调函数 class Container { protected $bindings = []; //绑定接口和生成相应实例的回调函数 public fu ...