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 相关文章推荐
Linux下Python获取IP地址的代码
Nov 30 Python
django1.8使用表单上传文件的实现方法
Nov 04 Python
Python二叉树的定义及常用遍历算法分析
Nov 24 Python
Python中max函数用于二维列表的实例
Apr 03 Python
Django中使用Celery的教程详解
Aug 24 Python
libreoffice python 操作word及excel文档的方法
Jul 04 Python
Python 实现一个手机号码获取妹子名字的功能
Sep 25 Python
python实现修改固定模式的字符串内容操作示例
Dec 30 Python
详解python程序中的多任务
Sep 16 Python
Python fileinput模块如何逐行读取多个文件
Oct 05 Python
Python开发.exe小工具的详细步骤
Jan 27 Python
Python pandas求方差和标准差的方法实例
Aug 04 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
fleaphp rolesNameField bug解决方法
2011/04/23 PHP
PHP的构造方法,析构方法和this关键字详细介绍
2013/10/22 PHP
PHP中使用addslashes函数转义的安全性原理分析
2014/11/03 PHP
getElementsByTagName vs selectNodes效率 及兼容的selectNodes实现
2010/02/26 Javascript
jQuery 源码分析笔记(5) jQuery.support
2011/06/19 Javascript
jQuery 瀑布流 绝对定位布局(二)(延迟AJAX加载图片)
2012/05/23 Javascript
基于jquery的禁用右键、文本选择功能、复制按键的实现代码
2013/08/27 Javascript
当鼠标滑过文本框自动选中输入框内容的JS代码分享
2013/11/26 Javascript
jquery动态加载select下拉框示例代码
2013/12/10 Javascript
深入理解JavaScript系列(31):设计模式之代理模式详解
2015/03/03 Javascript
jquery弹出遮掩层效果【附实例代码】
2016/04/28 Javascript
在微信、支付宝、百度钱包实现点击返回按钮关闭当前页面和窗口的方法
2016/08/05 Javascript
jQuery插件zTree实现清空选中第一个节点所有子节点的方法
2017/03/08 Javascript
Vue-cli proxyTable 解决开发环境的跨域问题详解
2017/05/18 Javascript
详解A标签中href=""的几种用法
2017/08/20 Javascript
Node.js实现注册邮箱激活功能的方法示例
2018/03/23 Javascript
vue实现抖音时间转盘
2019/09/08 Javascript
[54:41]2018DOTA2亚洲邀请赛3月30日 小组赛B组 VGJ.T VS paiN
2018/03/31 DOTA
python语言使用技巧分享
2016/05/31 Python
Pyinstaller将py打包成exe的实例
2018/03/31 Python
python中利用numpy.array()实现俩个数值列表的对应相加方法
2019/08/26 Python
Django实现从数据库中获取到的数据转换为dict
2020/03/27 Python
Python实现哲学家就餐问题实例代码
2020/11/09 Python
HTML5 预加载让页面得以快速呈现
2013/08/13 HTML / CSS
Bose加拿大官方网站:美国知名音响品牌
2019/03/21 全球购物
美国环保妈妈、儿童和婴儿用品购物网站:The Tot
2019/11/24 全球购物
添柏岚英国官方网站:Timberland英国
2019/11/28 全球购物
锐步英国官网:Reebok英国
2019/11/29 全球购物
施工安全责任书
2014/04/14 职场文书
2014年党支部学习材料
2014/05/19 职场文书
医学专业大学生求职信
2014/07/12 职场文书
企业趣味活动方案
2014/08/21 职场文书
正风肃纪剖析材料
2014/09/30 职场文书
公司财务部岗位职责
2015/04/14 职场文书
付款证明格式范文
2015/06/19 职场文书
一次SQL查询优化原理分析(900W+数据从17s到300ms)
2022/06/10 SQL Server