学习了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随笔的更多相关文章

  1. AI人工智能系列随笔

    初探 AI人工智能系列随笔:syntaxnet 初探(1)

  2. 【置顶】CoreCLR系列随笔

    CoreCLR配置系列 在Windows上编译和调试CoreCLR GC探索系列 C++随笔:.NET CoreCLR之GC探索(1) C++随笔:.NET CoreCLR之GC探索(2) C++随笔 ...

  3. C++随笔:.NET CoreCLR之GC探索(4)

    今天继续来 带大家讲解CoreCLR之GC,首先我们继续看这个GCSample,这篇文章是上一篇文章的继续,如果有不清楚的,还请翻到我写的上一篇随笔.下面我们继续: // Initialize fre ...

  4. C++随笔:从Hello World 探秘CoreCLR的内部(1)

    紧接着上次的问题,上次的问题其实很简单,就是HelloWorld.exe运行失败,而本文的目的,就是成功调试HelloWorld这个控制台应用程序. 通过我的寻找,其实是一个名为TryRun的文件出了 ...

  5. ASP.NET MVC 系列随笔汇总[未完待续……]

    ASP.NET MVC 系列随笔汇总[未完待续……] 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的. 学前篇之: ASP.NET MVC学前篇之扩展方法.链式编程 ASP. ...

  6. Mina、Netty、Twisted一起学(八):HTTP服务器

    HTTP协议应该是目前使用最多的应用层协议了,用浏览器打开一个网站就是使用HTTP协议进行数据传输. HTTP协议也是基于TCP协议,所以也有服务器和客户端.HTTP客户端一般是浏览器,当然还有可能是 ...

  7. 使用Beautiful Soup编写一个爬虫 系列随笔汇总

    这几篇博文只是为了记录学习Beautiful Soup的过程,不仅方便自己以后查看,也许能帮到同样在学习这个技术的朋友.通过学习Beautiful Soup基础知识 完成了一个简单的爬虫服务:从all ...

  8. 利用Python进行数据分析 基础系列随笔汇总

    一共 15 篇随笔,主要是为了记录数据分析过程中的一些小 demo,分享给其他需要的网友,更为了方便以后自己查看,15 篇随笔,每篇内容基本都是以一句说明加一段代码的方式, 保持简单小巧,看起来也清晰 ...

  9. 《高性能javascript》 领悟随笔之-------DOM编程篇(二)

    <高性能javascript> 领悟随笔之-------DOM编程篇二 序:在javaSctipt中,ECMASCRIPT规定了它的语法,BOM实现了页面与浏览器的交互,而DOM则承载着整 ...

随机推荐

  1. python之最强王者(5)——Nunber(数字)

    1.Python Number(数字) Python Number 数据类型用于存储数值. 数据类型是不允许改变的,这就意味着如果改变 Number 数据类型的值,将重新分配内存空间. 以下实例在变量 ...

  2. 供应链需求调研CheckList

    总体(General) 基本情况 1.    企业地址.邮编.电话.传真,项目联系人等基本资料. 2.    企业经营范围,产品线和主导产品. 3.    企业近几年的产值及销售额. 4.    企业 ...

  3. CSS3新特性应用之字体排印

    一.插入换行 ~:表示同辈元素之后指定类型的元素,如;elm1 ~ elm2表示,elm1之后的所有elm2元素,且elm1与elm2都是在同一个父级元素. +:表示同辈元素的兄弟元素. \A:一个空 ...

  4. 【前端优化之渲染优化】大屏android手机动画丢帧的背后

    前言 上周我与阿里的宇果有一次技术的交流,然后对天猫H5站点做了一些浅层次的分析,后面点时间基本天天都会有联系,中途聊了一些技术细节.聊了双方团队在干什么,最后聊到了前端优化.因为我本身参与了几次携程 ...

  5. JavaScript闭包(Closure)

    JavaScript闭包(Closure) 本文收集了多本书里对JavaScript闭包(Closure)的解释,或许会对理解闭包有一定帮助. <你不知道的JavsScript> Java ...

  6. Unable to download data from http://ruby.taobao.org/ & don't have write permissions for the /Library/Ruby/Gems/2.0.0 directory.

    安装cocoapods,记录两个问题! 1.镜像已经替换成了 http://ruby.taobao.org/, 还是不能不能安装cocoapods, 报错:Unable to download dat ...

  7. Appfuse:权限控制

    Appfuse的权限控制依赖于Struts的Menu机制,common下的menu.jsp是对菜单顺序的定义,详细的菜单项和菜单链接及权限再menu-config.xml中控制,如下: <Men ...

  8. 前端开发--评论区抓bug

    1. 工程地址:https://github.com/digitalClass/web_page 网站发布地址: http://115.28.30.25:8029/ ppt展示页面: http://1 ...

  9. having过滤语句

    having 对部分分组来进行过滤 跟在group by 后面 在having语句中不能包含未分组的列名, select FAge,COUNT(*) from T_Employee  where FS ...

  10. QStatusBar的用法

      QStatusBa,状态栏是位于主窗口的最下方,提供一个显示工具提示等信息的地方.QMainWindow类里面就有一个statusBar()函数,用于实现状态栏的调用.以下例子都在QMainWin ...