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 相关文章推荐
Python微信库:itchat的用法详解
Aug 14 Python
Python中摘要算法MD5,SHA1简介及应用实例代码
Jan 09 Python
Python lambda函数基本用法实例分析
Mar 16 Python
python中scikit-learn机器代码实例
Aug 05 Python
python判断列表的连续数字范围并分块的方法
Nov 16 Python
python实现贪吃蛇小游戏
Mar 21 Python
详解Python二维数组与三维数组切片的方法
Jul 18 Python
关于numpy数组轴的使用详解
Dec 05 Python
Python enumerate内置库用法解析
Feb 24 Python
基于python实现查询ip地址来源
Jun 02 Python
python 服务器运行代码报错ModuleNotFoundError的解决办法
Sep 16 Python
Python lxml库的简单介绍及基本使用讲解
Dec 22 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
如何使用PHP实现javascript的escape和unescape函数
2013/06/29 PHP
fckeditor上传文件按日期存放及重命名方法
2015/05/22 PHP
深入理解PHP内核(二)之SAPI探究
2015/11/10 PHP
php基于环形链表解决约瑟夫环问题示例
2017/11/07 PHP
PHP之认识(二)关于Traits的用法详解
2019/04/11 PHP
js兼容标准的表格变色效果
2008/06/28 Javascript
jQuery 操作下拉列表框实现代码
2010/02/22 Javascript
JavaScript中“基本类型”之争小结
2013/01/03 Javascript
JavaScript正则表达式的分组匹配详解
2016/02/13 Javascript
基于jQuery实现滚动切换效果
2016/12/02 Javascript
webpack入门+react环境配置
2017/02/08 Javascript
Vue数组更新及过滤排序功能
2017/08/10 Javascript
bootstrap fileinput实现文件上传功能
2017/08/23 Javascript
基于vue中解决v-for使用报红并出现警告的问题
2018/03/03 Javascript
解决node修改后需频繁手动重启的问题
2018/05/13 Javascript
JavaScript+HTML5 canvas实现放大镜效果完整示例
2019/05/15 Javascript
深入学习JavaScript 高阶函数
2019/06/11 Javascript
TypeScript类型声明书写详解
2019/08/28 Javascript
VUE 组件转换为微信小程序组件的方法
2019/11/06 Javascript
vue-父子组件和ref实例详解
2019/11/10 Javascript
JS造成内存泄漏的几种情况实例分析
2020/03/02 Javascript
[02:14]DOTA2英雄基础教程 修补匠
2013/12/23 DOTA
Python中的Numpy矩阵操作
2018/08/12 Python
selenium 安装与chromedriver安装的方法步骤
2019/06/12 Python
教你如何编写、保存与运行Python程序的方法
2019/07/12 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
2019/07/22 Python
利用python-pypcap抓取带VLAN标签的数据包方法
2019/07/23 Python
Python实现bilibili时间长度查询的示例代码
2020/01/14 Python
Python解析m3u8拼接下载mp4视频文件的示例代码
2021/03/03 Python
计算机系毕业生推荐信
2013/11/06 职场文书
小学生检讨书大全
2014/02/06 职场文书
中国好声音华少广告词
2014/03/17 职场文书
公开承诺书格式
2014/05/21 职场文书
有限责任公司股东合作协议书范本
2014/10/30 职场文书
生产设备维护保养制度
2015/08/06 职场文书
Win10本地连接不见了怎么恢复? win10系统电脑本地连接不见了解决方法
2023/01/09 数码科技