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的Flask框架中集成CKeditor富文本编辑器的教程
Jun 13 Python
对numpy数据写入文件的方法讲解
Jul 09 Python
人工神经网络算法知识点总结
Jun 11 Python
如何使用Python自动控制windows桌面
Jul 11 Python
使用keras根据层名称来初始化网络
May 21 Python
Django serializer优化类视图的实现示例
Jul 16 Python
Python打印不合法的文件名
Jul 31 Python
pycharm配置QtDesigner的超详细方法
Jan 25 Python
python向xls写入数据(包括合并,边框,对齐,列宽)
Feb 02 Python
解决jupyter notebook启动后没有token的坑
Apr 24 Python
Python 中的单分派泛函数你真的了解吗
Jun 22 Python
python数据处理之Pandas类型转换
Apr 28 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+MYSQL的文章管理系统(一)
2006/10/09 PHP
android上传图片到PHP的过程详解
2015/08/03 PHP
PHP读取大文件的多种方法介绍
2016/04/04 PHP
PHP中模糊查询并关联三个select框
2017/06/19 PHP
thinkPHP中钩子的使用方法实例分析
2017/11/16 PHP
PHP Web表单生成器案例分析
2020/06/02 PHP
js实现兼容IE6与IE7的DIV高度
2010/05/13 Javascript
ajaxFileUpload.js插件支持多文件上传的方法
2014/09/02 Javascript
基于jQuery实现复选框的全选 全不选 反选功能
2014/11/24 Javascript
jQuery操作表单常用控件方法小结
2015/03/23 Javascript
简单谈谈node.js 版本控制 nvm和 n
2015/10/15 Javascript
jQuery EasyUI框架中的Datagrid数据表格组件结构详解
2016/06/09 Javascript
一种基于浏览器的自动小票机打印实现方案(js版)
2016/07/26 Javascript
Vuex模块化实现待办事项的状态管理
2017/03/15 Javascript
微信小程序实现指定显示行数多余文字去掉用省略号代替
2018/07/25 Javascript
JavaScript中变量提升与函数提升经典实例分析
2018/07/26 Javascript
详解Vue.js v-for不支持IE9的解决方法
2018/12/29 Javascript
微信小程序自定义组件实现环形进度条
2020/11/17 Javascript
Vue 3.x+axios跨域方案的踩坑指南
2019/07/04 Javascript
JS数组Reduce方法功能与用法实例详解
2020/04/29 Javascript
python使用socket向客户端发送数据的方法
2015/04/29 Python
python实现读取命令行参数的方法
2015/05/22 Python
使用Python对SQLite数据库操作
2017/04/06 Python
Python math库 ln(x)运算的实现及原理
2019/07/17 Python
Django如何实现密码错误报错提醒
2020/09/04 Python
Kathmandu澳洲户外商店:新西兰户外运动品牌
2017/11/12 全球购物
护士演讲稿范文
2014/01/05 职场文书
上班玩游戏检讨书
2014/02/07 职场文书
银行爱岗敬业演讲稿
2014/05/05 职场文书
奥巴马开学演讲稿
2014/05/15 职场文书
工地门卫岗位职责范本
2014/07/01 职场文书
开会通知短信大全
2015/04/20 职场文书
大学生社会实践感想
2015/08/11 职场文书
《秋思》教学反思
2016/02/23 职场文书
2019自荐信该如何写呢?
2019/07/05 职场文书
使用Canvas绘制一个游戏人物属性图
2022/03/25 Javascript