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的Supervisor进行进程监控以及自动启动
May 29 Python
Python 实现链表实例代码
Apr 07 Python
python实现各进制转换的总结大全
Jun 18 Python
Python基于matplotlib绘制栈式直方图的方法示例
Aug 09 Python
python实现PID算法及测试的例子
Aug 08 Python
使用python将excel数据导入数据库过程详解
Aug 27 Python
python读取ini配置文件过程示范
Dec 23 Python
Python AutoCAD 系统设置的实现方法
Apr 01 Python
python 错误处理 assert详解
Apr 20 Python
Python 实现微信自动回复的方法
Sep 11 Python
python使用glob检索文件的操作
May 20 Python
python 常用的异步框架汇总整理
Jun 18 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
phpexcel导出excel的颜色和网页中的颜色显示不一致
2012/12/11 PHP
解析PHP强制转换类型及远程管理插件的安全隐患
2014/06/30 PHP
PHP文件上传类实例详解
2016/04/08 PHP
详解php中serialize()和unserialize()函数
2017/07/08 PHP
Alliance vs Liquid BO3 第二场2.13
2021/03/10 DOTA
JavaScript中的Document文档对象
2008/01/16 Javascript
初学js 新节点的创建 删除 的步骤
2011/07/04 Javascript
form.submit()不能提交表单的错误原因及解决方法
2014/10/13 Javascript
一款基jquery超炫的动画导航菜单可响应单击事件
2014/11/02 Javascript
JQuery遍历json数组的3种方法
2014/11/08 Javascript
推荐一个自己用的封装好的javascript插件
2015/01/29 Javascript
javascript日期验证之输入日期大于等于当前日期
2015/12/13 Javascript
JavaScript获取ul中li个数的方法
2017/02/13 Javascript
基于jQuery Easyui实现登陆框界面
2017/07/10 jQuery
Angular实现类似博客评论的递归显示及获取回复评论的数据
2017/11/06 Javascript
Vue中的vue-resource示例详解
2018/11/02 Javascript
vue调用语音播放的方法
2019/09/27 Javascript
微信小程序去除左上角返回键的实现方法
2020/03/06 Javascript
js实现淘宝浏览商品放大镜功能
2020/10/28 Javascript
vue mvvm数据响应实现
2020/11/11 Javascript
Antd-vue Table组件添加Click事件,实现点击某行数据教程
2020/11/17 Javascript
[02:39]DOTA2国际邀请赛助威团西雅图第一天
2013/08/08 DOTA
django实现分页的方法
2015/05/26 Python
Python运算符重载详解及实例代码
2017/03/07 Python
Python 一句话生成字母表的方法
2019/01/02 Python
对python以16进制打印字节数组的方法详解
2019/01/24 Python
关于python导入模块import与常见的模块详解
2019/08/28 Python
谈谈python垃圾回收机制
2020/09/27 Python
意大利奢侈品购物网站:Deliberti
2019/10/08 全球购物
澳大利亚领先的亚麻品牌:Bed Threads
2019/12/16 全球购物
新年抽奖获奖感言
2014/03/02 职场文书
就业协议书怎么填
2014/04/11 职场文书
教研处工作方案
2014/05/26 职场文书
2014年企业团支部工作总结
2014/12/10 职场文书
工厂采购员岗位职责
2015/04/07 职场文书
GTX1660显卡搭配显示器推荐
2022/04/19 数码科技