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实现探测socket和web服务示例
Mar 28 Python
python静态方法实例
Jan 14 Python
Python实现翻转数组功能示例
Jan 12 Python
python实现类之间的方法互相调用
Apr 29 Python
Python使用Flask-SQLAlchemy连接数据库操作示例
Aug 31 Python
屏蔽Django admin界面添加按钮的操作
Mar 11 Python
Jupyter Notebook打开任意文件夹操作
Apr 14 Python
python实现扑克牌交互式界面发牌程序
Apr 22 Python
Python3.7下安装pyqt5的方法步骤(图文)
May 12 Python
PyQT5 实现快捷键复制表格数据的方法示例
Jun 19 Python
python中random模块详解
Mar 01 Python
Python 统计序列中元素的出现频度
Apr 26 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文章采集URL补全函数(FormatUrl)
2012/08/02 PHP
ECMall支持SSL连接邮件服务器的配置方法详解
2014/05/19 PHP
PHP批量生成图片缩略图的方法
2015/06/18 PHP
php提高网站效率的技巧
2015/09/29 PHP
YII动态模型(动态表名)支持分析
2016/03/29 PHP
Yii中的cookie的发送和读取
2016/07/27 PHP
JavaScript 继承机制的实现(待续)
2010/05/18 Javascript
基于jquery实现的表格分页实现代码
2011/06/21 Javascript
封装了一个js图片轮换效果的函数
2011/09/28 Javascript
浅谈jquery.fn.extend与jquery.extend区别
2015/07/13 Javascript
JS实现星星评分功能实例代码(两种方法)
2016/06/09 Javascript
微信小程序 scroll-view隐藏滚动条详解
2017/01/16 Javascript
基于Bootstrap分页的实例讲解(必看篇)
2017/07/04 Javascript
基于JQuery的Ajax方法使用详解
2017/08/16 jQuery
vue-router 手势滑动触发返回功能
2018/09/30 Javascript
微信小程序实现左右列表联动
2020/05/19 Javascript
Layui实现数据表格中鼠标悬浮图片放大效果,离开时恢复原图的方法
2019/09/11 Javascript
vue vantUI实现文件(图片、文档、视频、音频)上传(多文件)
2019/10/15 Javascript
云服务器部署Node.js项目的方法步骤(小白系列)
2020/03/23 Javascript
python实现任意位置文件分割的实例
2018/12/14 Python
详解如何用python实现一个简单下载器的服务端和客户端
2019/10/28 Python
详解Python中的路径问题
2020/09/02 Python
HTML5之SVG 2D入门3—文本与图像及渲染文本介绍
2013/01/30 HTML / CSS
美国摄影爱好者购物网站:Focus Camera
2016/10/21 全球购物
美国床垫和床上用品公司:Nest Bedding
2017/06/12 全球购物
世界上最大的糖果店:Dylan’s Candy Bar
2017/11/07 全球购物
缅甸网上购物:Shop.com.mm
2017/12/05 全球购物
澳大利亚领先的时尚内衣零售商:Bras N Things
2020/07/28 全球购物
学生自我鉴定范文
2013/10/04 职场文书
仓库组长岗位职责
2014/01/29 职场文书
服装行业创业计划书范文
2014/02/05 职场文书
三八妇女节活动总结
2014/05/04 职场文书
质量提升方案
2014/06/16 职场文书
学校勤俭节约倡议书
2015/04/29 职场文书
[有人@你]你有一封绿色倡议书,请查收!
2019/07/18 职场文书
彻底弄懂Python中的回调函数(callback)
2022/06/25 Python