利用python-twisted库实现一个文件收发服务

最近在学习python-twisted库,之前做异步并发编程一直都是使用c++,比如linux下的epoll机制,windows的IOCP机制,到后来经常使用的Boost::Asio库,比较搞的是c++上的异步经验反而有点阻碍我开始学习twisted库,原因如下:

不管是epoll还是IOCP,都是当读操作或者写操作可执行时(IOCP则是完成时)会得到一个通知,然后可以执行自己的下一步代码。这种情景下如果你是做较大数据的收发的话,就可以在得到通知时进行必要的处理后继续发送或者接受下一个数据块,但是twisted的库则不是这样设计的,以twisted.protocols.basic.LineReceiver为例,当异步收到数据后,该类的lineReceived函数或者rawDataReceived(取决于当前的模式)会被触发,但是它并不包含异步写函数,也就是说你无法这样操作:

1、调用异步发送函数发送数据

2、数据发送完成时触发一个回调函数

3、在该回调函数中你决定后续的操作,比如继续发送下一块数据

那么twisted的解决方案是什么?答案是producer/consumer ,producer负责源源不断的产生数据(如不断从file中读取数据),consumer负责处理数据(通过socket发送出去),当consumer在发送时缓存满了它会通知producer暂停提供数据,当缓存清空后继续通知producer产生数据(这就类似我们上面提到的,当异步发送完成时调用一个回调函数),这个的过程不需要我们在代码中显示的控制。由于文件发送应用的普遍性,twisted提供了一个文件发送类FileSender,好啦,描述性的内容就到这里,后续关于producer/consumer我会进一步介绍,下面直接上代码

from twisted.internet.protocol import Protocol,Factory
from twisted.protocols.basic import LineReceiver
from twisted.protocols.basic import FileSender
from twisted.internet.defer import Deferred
import pickle,struct
import multiprocessing.pool
import os,json

class TransferFileProtocol(LineReceiver):
    port_ = 0
    def __init__(self):
        self.handle_f_ = None
        #--------------------------
        self.instruction_ = None
        self.command_ = None
        self.size_remain_ = 0
        #self.setRawMode()
    def _monitor(self,data):
        self.size_remain_-=len(data)
        return data

    def cbTransferOver(self, lastSent):
        print(‘download over!‘)
        self.transport.loseConnection()

    def connectionMade(self):
        print(‘Got Connection from ‘,self.transport.client)
        print ‘work on port:%d‘ % (self.port_,)

    def connectionLost(self,reason):
        print(self.transport.client, ‘ disconnected!‘)
        if self.handle_f_ != None:
            self.handle_f_.close()
        if self.size_remain_ != 0:
            print ‘transfer file fail!‘
#            if self.command_ == ‘put‘:
#                os.

    def lineReceived(self, line):
        self.instruction_ = json.loads(line)
        self.command_ = self.instruction_[‘command‘]
        name_file = self.instruction_[‘name_file‘]
        if self.command_ == ‘put‘:
            self.size_remain_ = self.instruction_[‘size_file‘]
            try:
                self.handle_f_ = open(‘files/%s‘ % (name_file,),‘wb‘)
            except:
                print ‘open %s fail!‘ % (name_file,)
                self.handle_f_ = None
#                self.transfer.loseConnection()
            else:
                self.setRawMode()
        elif ‘get‘ == self.command_:
            self.size_remain_ = 0
            if os.path.exists(‘files/%s‘ % (name_file,)):
                self.size_remain_ = os.stat(‘files/%s‘ % (name_file,)).st_size
            instruction = dict(size_file=self.size_remain_)
            if self.size_remain_>0:
                try:
                    self.handle_f_ = open(‘files/%s‘ % (name_file,),‘rb‘)
                except:
                    self.size_remain_ = 0
                    self.handle_f_ = None
                else:
                    self.setRawMode()
            self.transport.write(json.dumps(instruction)+‘\r\n‘)
            if self.size_remain_>0:
                sender = FileSender()
                sender.CHUNCK_SIZE = 2**16
                d = sender.beginFileTransfer(self.handle_f_,self.transport,self._monitor)
                d.addCallback(self.cbTransferOver)

    def rawDataReceived(self, data):
        print ‘length of data:%d‘ % (len(data),)
        if ‘put‘ == self.command_ and self.handle_f_ != None:
            self.handle_f_.write(data)
            self.size_remain_ -= len(data)

def recv_func(port):
    from twisted.internet import epollreactor
    epollreactor.install()
    from twisted.internet import reactor
    TransferFileProtocol.port_ = port
    factory = Factory()
    factory.protocol = TransferFileProtocol
    reactor.listenTCP(port,factory)
    reactor.run()

if __name__ ==‘__main__‘:
    ports = [6200,6202,6204,6206]
    pool = multiprocessing.pool.Pool(len(ports))
    pool.map(recv_func,ports)
#    recv_func(6200)
时间: 2024-08-06 09:18:56

利用python-twisted库实现一个文件收发服务的相关文章

利用Python原始库完成一个端口扫描的功能

import socket def get_ip_status(ip,port): server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: server.connect((ip,port)) print('{0} port {1} is open'.format(ip, port)) except Exception as err: print('{0} port {1} is not open'.format(ip,por

shell实现自动备份整个数据库,一个库备份一个文件

自动实现备份整个数据库 实现一个库备份一个文件 实现排除不需要备份的库 实现备份成压缩文件 实现定义保留多少天的备份文件 核心代码 1 #!/bin/bash 2 #set -x 3 ######################### 4 # 功能:自动备份整个mysql数据库 5 # 作者:时光博客 6 # 发布时间:2018/06/04 7 # 最后修改时间: 8 # 版本:v1.0 9 ######################## 10 ########################

python标准库之shutil文件

import shutil,glob,os#作用:处理一些文件操作,如复制,设置权限#复制文件copyfile()将源内容复制到目标,如果没有权限写目标文件则产生 ioerrorprint 'before:',glob.glob('*.txt')shutil.copyfile('lorem.txt',r'copy/lorem.txt')print 'after:',glob.glob(r'copy/lorem.txt')#由于这个函数会打开输入文件进行读取,而不论其类型,所以某些特殊文件(如un

利用Python将多个PDF文件合并

from PyPDF2 import PdfFileMerger import os files = os.listdir()#列出目录中的所有文件 merger = PdfFileMerger() for file in files: #从所有文件中选出pdf文件合并 if file[-4:] == ".pdf": merger.append(open(pdf, 'rb')) with open('newfile.pdf', 'wb') as fout: #输出文件为newfile.

利用python脚本把多个文件内容放到一个文件内

说明:path是你所有文件存放的目录,先去循环所有的文件内容,然后写入到test.xls文件里 import os path = 'file' # path=r'D:\file' for filename in os.listdir(path): fullname = os.path.join(path, filename) # 如果是linux系统导出来的数据用utf-8,如果是windows则用gbk f1 = open(fullname, encoding='gbk') for i in

利用python同步windows和linux文件

写python脚本的初衷,每次在windows编辑完文件后,想同步到linux上去,只能够登录服务器,然后再利用网络copy,重复性很大,就想着能不能写一个小脚本帮我同步 逻辑:比对本地和服务器文件的md5,如果md5不一致,则备份服务器上的文件,将本地的给上传上去 代码分为windows端和服务器端,有些东西,都让python一个做了,写着有点累,就想着,能否服务端提供一个端口,windows去调用这个接口,来完成一部分工作 python代码如下: 需要额外安装的包为是paramiko,安装方

Python实现重命名一个文件夹下的图片

在网上查了一下python实现的图片重命名,工作中刚好用一下. 1 # -*- coding:utf8 -*- 2 import os 3 path = '新建文件夹 (2)/' 4 filelist = os.listdir(path) 5 for item in filelist: 6 # print('item name is ',item) 7 if item.endswith('.jpg'): 8 name = item.split('.',1)[0] 9 src = os.path.

用python requests库写一个人人网相册爬虫

担心人人网会黄掉,写个爬虫,把我的相册照片都下载下来.代码如下: # -*- coding: utf-8 -*- import requests import json import os def mkdir(path): path=path.strip() path=path.rstrip("\\") isExists=os.path.exists(path) if not isExists: print path+u' 创建成功' os.makedirs(path) else: p

利用Python读取Matlab的Mat文件内容

手头有别人写的Matlab程序,其中用到了Mat文件.现在不想安装Matlab,却又想读取Mat文件内容,该怎么办呢? 感谢scipy!!! 1 import scipy.io 2 3 data = scipy.io.loadmat('1.mat') # 假设文件名为1.mat 4 # data类型为dictionary 5 print data.keys() # 即可知道Mat文件中存在数据名,假设存在'x', 'y'两列数据 6 print data['x'] 7 print data['y