Python 基于Twisted框架的文件夹网络传输源码


Posted in Python onAugust 28, 2016

由于文件夹可能有多层目录,因此需要对其进行递归遍历。

本文采取了简单的协议定制,定义了五条命令,指令Head如下:
Sync:标识开始同步文件夹
End:标识结束同步
File:标识传输的文件名(相对路径)
Folder:标志文件夹(相对路径)
None:文件内容

每条命令以CMB_BEGIN开始,以CMB_END结束。

客户端需要对接收缓冲做解析,取出一条一条的指令,然后根据指令的Head做相应的处理,比如创建文件夹、写入文件等。

下面是服务端的代码:

from twisted.internet import reactor
from twisted.internet.protocol import Protocol,Factory
from twisted.protocols.basic import LineReceiver
import os
import struct
 
BUFSIZE = 4096
 
class SimpleLogger(Protocol):
  def connectionMade(self):
    print 'Got connection from', self.transport.client
 
  def connectionLost(self, reason):
    print self.transport.client, 'disconnected'
 
  def dataReceived(self, line):
    print line
    self.transport.write("Hello Client, I am the Server!\r\n")
 
    self.transport.write("CMB_BEGIN")
    self.transport.write("Sync")
    self.transport.write("CMB_END")
    self.send_file_folder('server')
 
  def send_file_folder(self,folder):
    '''send folder to the client'''
    for f in os.listdir(folder):
      sourceF = os.path.join(folder, f)
      if os.path.isfile(sourceF):      
        print 'File:',sourceF[7:]
        self.transport.write("CMB_BEGIN")
        self.transport.write("File:" + sourceF[7:])
        self.transport.write("CMB_END")
        fp = open(sourceF,'rb')
        while 1:
          filedata = fp.read(BUFSIZE)
          if not filedata: break
          else:
            self.transport.write("CMB_BEGIN")
            self.transport.write(filedata)
            print 'send size:::::::::',len(filedata)
            self.transport.write("CMB_END")
        fp.close()
        self.transport.write("CMB_BEGIN")
        self.transport.write("End")
        self.transport.write("CMB_END")
      if os.path.isdir(sourceF):
        print 'Folder:',sourceF[7:]
        self.transport.write("CMB_BEGIN")
        self.transport.write("Folder:" + sourceF[7:])
        self.transport.write("CMB_END")
        self.send_file_folder(sourceF)
 
factory = Factory()
factory.protocol = SimpleLogger
reactor.listenTCP(1234, factory)
reactor.run()

Server在收到Client的某个信号之后(此代码中,当Client随便向Server发送任何内容都可),Server即会调用send_file_folder将sever文件夹下的内容全部发送给客户端。

服务端运行结果如下:

Python 基于Twisted框架的文件夹网络传输源码

下面是客户端的代码:

from twisted.internet.selectreactor import SelectReactor
from twisted.internet.protocol import Protocol,ClientFactory
from twisted.protocols.basic import LineReceiver
import os
from struct import *
 
reactor = SelectReactor()
protocol = Protocol()
prepare = 0
filename = ""
sourceDir = 'client'
recvBuffer = ''
 
def delete_file_folder(src):
  '''delete files and folders'''
  if os.path.isfile(src):
    try:
      os.remove(src)
    except:
      pass
  elif os.path.isdir(src):
    for item in os.listdir(src):
      itemsrc = os.path.join(src,item)
      delete_file_folder(itemsrc) 
    try:
      os.rmdir(src)
    except:
      pass
 
def clean_file_folder(src):
  '''delete files and child folders'''
  delete_file_folder(src)
  os.mkdir(src)
 
def writefile(filename,data):
  print 'write file size:::::::::',len(data)
  fp = open(filename,'a+b')
  fp.write(data)
  fp.close()
 
class QuickDisconnectedProtocol(Protocol):
  def connectionMade(self):
    print "Connected to %s."%self.transport.getPeer().host
    self.transport.write("Hello server, I am the client!\r\n")
  def dataReceived(self, line):
    global prepare
    global filename
    global sourceDir
    global recvBuffer
 
    recvBuffer = recvBuffer + line
    self.processRecvBuffer()
 
  def processRecvBuffer(self):
    global prepare
    global filename
    global sourceDir
    global recvBuffer
 
    while len(recvBuffer) > 0 :
      index1 = recvBuffer.find('CMB_BEGIN')
      index2 = recvBuffer.find('CMB_END')
 
      if index1 >= 0 and index2 >= 0:
        line = recvBuffer[index1+9:index2]
        recvBuffer = recvBuffer[index2+7:]
 
        if line == 'Sync':
          clean_file_folder(sourceDir)
 
        if line[0:3] == "End":
          prepare = 0
        elif line[0:5] == "File:":
          name = line[5:]
          filename = os.path.join(sourceDir, name)
          print 'mk file:',filename
          prepare = 1
        elif line[0:7] == "Folder:":
          name = line[7:]
          filename = os.path.join(sourceDir, name)
          print 'mkdir:',filename
          os.mkdir(filename)
        elif prepare == 1:
          writefile(filename,line)
      else:
        break 
 
class BasicClientFactory(ClientFactory):
  protocol=QuickDisconnectedProtocol
  def clientConnectionLost(self,connector,reason):
    print 'Lost connection: %s'%reason.getErrorMessage()
    reactor.stop()
  def clientConnectionFailed(self,connector,reason):
    print 'Connection failed: %s'%reason.getErrorMessage()
    reactor.stop()
 
reactor.connectTCP('localhost',1234,BasicClientFactory())
reactor.run()

客户端提取出来自Server的指令,当提取出Sync指令时,则将sourceDir目录清空,然后根据后续的指令,跟Server的文件夹进行同步。

客户端运行结果如下:

Python 基于Twisted框架的文件夹网络传输源码

需要注意的地方:
Client写入文件时,需要以二进制的方式打开文件,否则,在传输二进制文件时可能出现错误或导致文件损坏。

经过测试,代码可以正常的运行,文件夹同步成功,文本文件、图像和其他类型的二进制文件均可正常传输。

Python 相关文章推荐
使用grappelli为django admin后台添加模板
Nov 18 Python
在Django的模型中执行原始SQL查询的方法
Jul 21 Python
举例讲解Linux系统下Python调用系统Shell的方法
Nov 07 Python
python+selenium开发环境搭建图文教程
Aug 11 Python
Python实现的摇骰子猜大小功能小游戏示例
Dec 18 Python
和孩子一起学习python之变量命名规则
May 27 Python
Django 使用Ajax进行前后台交互的示例讲解
May 28 Python
python中的常量和变量代码详解
Jul 25 Python
Python数据分析matplotlib设置多个子图的间距方法
Aug 03 Python
Django之使用celery和NGINX生成静态页面实现性能优化
Oct 08 Python
PyCharm下载和安装详细步骤
Dec 17 Python
浅谈优化Django ORM中的性能问题
Jul 09 Python
Django URL传递参数的方法总结
Aug 28 #Python
python 网络编程常用代码段
Aug 28 #Python
Fabric 应用案例
Aug 28 #Python
Python两个内置函数 locals 和globals(学习笔记)
Aug 28 #Python
Python 提取dict转换为xml/json/table并输出的实现代码
Aug 28 #Python
python解决方案:WindowsError: [Error 2]
Aug 28 #Python
详解Python中的文件操作
Aug 28 #Python
You might like
Look And Say 序列php实现代码
2011/05/22 PHP
PHP超级全局变量数组小结
2012/10/04 PHP
PHP与Java进行通信的实现方法
2013/10/21 PHP
php防止伪造数据从地址栏URL提交的方法
2014/08/24 PHP
php使用curl_init()和curl_multi_init()多线程的速度比较详解
2018/08/15 PHP
php swoole多进程/多线程用法示例【基于php7nts版】
2019/08/12 PHP
javascript css在IE和Firefox中区别分析
2009/02/18 Javascript
COM中获取JavaScript数组大小的代码
2009/11/22 Javascript
下载文件个别浏览器文件名乱码解决办法
2013/03/19 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
JavaScript中number转换成string介绍
2014/12/31 Javascript
React进阶学习之组件的解耦之道
2017/08/07 Javascript
AngularJS 中ui-view传参的实例详解
2017/08/25 Javascript
基于vue、react实现倒计时效果
2019/08/26 Javascript
ES2020 已定稿,真实场景案例分析
2020/05/25 Javascript
[38:38]完美世界DOTA2联赛PWL S3 access vs Rebirth 第二场 12.17
2020/12/18 DOTA
Python中线程编程之threading模块的使用详解
2015/06/23 Python
Python 结巴分词实现关键词抽取分析
2017/10/21 Python
Python3.5实现的罗马数字转换成整数功能示例
2019/02/25 Python
python中bytes和str类型的区别
2019/10/21 Python
PyTorch实现重写/改写Dataset并载入Dataloader
2020/07/14 Python
Python函数__new__及__init__作用及区别解析
2020/08/31 Python
Python大批量搜索引擎图像爬虫工具详解
2020/11/16 Python
如何基于Python和Flask编写Prometheus监控
2020/11/25 Python
华为旗下电子商务平台:华为商城
2016/08/06 全球购物
Bally澳大利亚官网:瑞士奢侈品牌
2018/11/01 全球购物
澳大利亚在线床零售商:Bedworks
2020/09/01 全球购物
广州地球村科技数据库题目
2016/04/25 面试题
应届生的求职推荐信范文
2013/11/30 职场文书
大学生的网络创业计划书
2013/12/26 职场文书
退学证明范本3篇
2014/10/29 职场文书
实习单位推荐信
2015/03/27 职场文书
2015年药店工作总结
2015/04/20 职场文书
标准版个人借条怎么写?以及什么是借条?
2019/08/28 职场文书
python树莓派通过队列实现进程交互的程序分析
2021/07/04 Python
nginx 配置指令之location使用详解
2022/05/25 Servers