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学习小技巧之列表项的排序
May 20 Python
Python中表达式x += y和x = x+y 的区别详解
Jun 20 Python
python中利用Future对象回调别的函数示例代码
Sep 07 Python
python使用邻接矩阵构造图代码示例
Nov 10 Python
Pandas 数据框增、删、改、查、去重、抽样基本操作方法
Apr 12 Python
python实现按长宽比缩放图片
Jun 07 Python
在python中使用xlrd获取合并单元格的方法
Dec 26 Python
python匿名函数lambda原理及实例解析
Feb 07 Python
PyInstaller运行原理及常用操作详解
Jun 13 Python
浅谈Keras的Sequential与PyTorch的Sequential的区别
Jun 17 Python
python 对xml解析的示例
Feb 27 Python
Python实战实现爬取天气数据并完成可视化分析详解
Jun 16 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
乐信RP2100的电路分析和打磨
2021/03/02 无线电
php 使用post,get的一种简洁方式
2010/04/25 PHP
基于PHP创建Cookie数组的详解
2013/07/03 PHP
laravel框架查询数据集转为数组的两种方法
2019/10/10 PHP
JavaScript数组对象赋值用法实例
2015/08/04 Javascript
javascript如何实现暂停功能
2015/11/06 Javascript
基于JavaScript代码实现随机漂浮图片广告
2016/01/05 Javascript
你所未知的3种Node.js代码优化方式
2016/02/25 Javascript
Angularjs 动态改变title标题(兼容ios)
2016/12/29 Javascript
Vuex之理解Getters的用法实例
2017/04/19 Javascript
jquery获取链接地址和跳转详解(推荐)
2017/08/15 jQuery
详解Angular Forms中自定义ngModel绑定值的方式
2018/12/10 Javascript
深入Node TCP模块的理解
2019/03/13 Javascript
巧妙运用v-model实现父子组件传值的方法示例
2019/04/07 Javascript
详解vue页面首次加载缓慢原因及解决方案
2019/11/06 Javascript
JS面向对象编程基础篇(二) 封装操作实例详解
2020/03/03 Javascript
python基础教程之获取本机ip数据包示例
2014/02/10 Python
python 字符串只保留汉字的方法
2018/11/16 Python
Python + OpenCV 实现LBP特征提取的示例代码
2019/07/11 Python
SELENIUM自动化模拟键盘快捷键操作实现解析
2019/10/28 Python
Python Pandas 转换unix时间戳方式
2019/12/07 Python
Python交互环境下打印和输入函数的实例内容
2020/02/16 Python
比利时的在线灯具店:Lampen24.be
2019/07/01 全球购物
大学生优秀团员事迹材料
2014/01/30 职场文书
服装店营销方案
2014/03/10 职场文书
项目合作协议书范本
2014/04/16 职场文书
党员群众路线承诺书
2014/05/20 职场文书
化工专业求职信
2014/07/01 职场文书
大一工商管理职业生涯规划:有梦最美,行动相随
2014/09/18 职场文书
六查六看心得体会
2014/10/14 职场文书
婚前协议书怎么写,才具有法律效力呢 ?
2019/06/28 职场文书
使用这 6个Vue加载动画库来减少我们网站的跳出率
2021/05/18 Vue.js
Python图片检索之以图搜图
2021/05/31 Python
centos8安装nginx1.9.1的详细过程
2021/08/02 Servers
JavaScript的function函数详细介绍
2021/11/20 Javascript
Qt数据库应用之实现图片转pdf
2022/06/01 Java/Android