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入门篇之正则表达式
Oct 20 Python
python实现根据月份和日期得到星座的方法
Mar 27 Python
使用Python标准库中的wave模块绘制乐谱的简单教程
Mar 30 Python
python选择排序算法实例总结
Jul 01 Python
Python实现的最近最少使用算法
Jul 10 Python
深入解析Python设计模式编程中建造者模式的使用
Mar 02 Python
独特的python循环语句
Nov 20 Python
对python opencv 添加文字 cv2.putText 的各参数介绍
Dec 05 Python
在python中利用opencv简单做图片比对的方法
Jan 24 Python
基于Python实现用户管理系统
Feb 26 Python
如何使用python爬虫爬取要登陆的网站
Jul 12 Python
django框架ModelForm组件用法详解
Dec 11 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 radio 单选框获取与保持值的实现代码
2010/05/15 PHP
php下使用strpos需要注意 === 运算符
2010/07/17 PHP
PHP获取文件夹大小函数用法实例
2015/07/01 PHP
PHP封装的字符串加密解密函数
2015/12/18 PHP
Zend Framework教程之分发器Zend_Controller_Dispatcher用法详解
2016/03/07 PHP
PHP设计模式之适配器模式定义与用法详解
2018/04/03 PHP
javascript中字符串替换函数replace()方法与c# 、vb 替换有一点不同
2010/06/25 Javascript
原生javascript实现图片轮播效果代码
2010/09/03 Javascript
javascript中关于执行环境的杂谈
2011/08/14 Javascript
也说JavaScript中String类的replace函数
2011/09/22 Javascript
onkeyup,onkeydown和onkeypress的区别介绍
2013/10/21 Javascript
可编辑下拉框的2种实现方式
2014/06/13 Javascript
用循环或if语句从json中取数据示例
2014/08/18 Javascript
推荐一个封装好的getElementsByClassName方法
2014/12/02 Javascript
jquery+javascript编写国籍控件
2015/02/12 Javascript
js实现PC端根据IP定位当前城市地理位置
2017/02/22 Javascript
Node.js 回调函数实例详解
2017/07/06 Javascript
基于JavaScript实现无限加载瀑布流
2017/07/21 Javascript
详解基于vue的移动web app页面缓存解决方案
2017/08/03 Javascript
spirngmvc js传递复杂json参数到controller的实例
2018/03/29 Javascript
JS面向对象的程序设计相关知识小结
2018/05/26 Javascript
微信小程序实现文字无限轮播效果
2018/12/28 Javascript
Node 模块原理与用法详解
2020/05/13 Javascript
完美解决vue 中多个echarts图表自适应的问题
2020/07/19 Javascript
JS实现斐波那契数列的五种方式(小结)
2020/09/09 Javascript
[11:57]《一刀刀一天》第十七期:TI中国军团加油!
2014/05/26 DOTA
Python读取word文本操作详解
2018/01/22 Python
Django Admin中增加导出CSV功能过程解析
2019/09/04 Python
美国网上眼镜供应商:LEOTONY(眼镜、RX太阳镜和太阳镜)
2017/10/31 全球购物
中学生获奖感言
2014/02/04 职场文书
优秀毕业生事迹材料
2014/02/12 职场文书
培训主管的职业生涯规划
2014/03/06 职场文书
干部作风整顿自我剖析材料和整改措施
2014/09/18 职场文书
2014年仓管员工作总结
2014/11/18 职场文书
幼儿园六一主持词
2015/06/30 职场文书
2016毕业实习单位评语大全
2015/12/01 职场文书