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之不要红头文件(2)
Sep 28 Python
详解Python中的array数组模块相关使用
Jul 05 Python
Python中字典的setdefault()方法教程
Feb 07 Python
python编程实现归并排序
Apr 14 Python
浅谈python数据类型及类型转换
Dec 18 Python
Python实现的建造者模式示例
Aug 06 Python
python实现狄克斯特拉算法
Jan 17 Python
python语言元素知识点详解
May 15 Python
python pip源配置,pip配置文件存放位置的方法
Jul 12 Python
Python计算公交发车时间的完整代码
Feb 12 Python
python中JWT用户认证的实现
May 18 Python
python设置表格边框的具体方法
Jul 17 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的开合式多级菜单程序
2006/10/09 PHP
php限制上传文件类型并保存上传文件的方法
2015/03/13 PHP
php使用 readfile() 函数设置文件大小大小的方法
2017/08/11 PHP
php实现在线考试系统【附源码】
2018/09/18 PHP
PHP convert_cyr_string()函数讲解
2019/02/13 PHP
FF IE兼容性的修改小结
2009/09/02 Javascript
Jquery 插件开发笔记整理
2011/01/17 Javascript
基于Jquery的仿照flash放大图片效果代码
2011/03/16 Javascript
SeaJS 与 RequireJS 的差异对比
2014/12/08 Javascript
js实现统计字符串中特定字符出现个数的方法
2016/08/02 Javascript
AngularJS实现表单验证功能
2017/01/09 Javascript
Javascript实现的StopWatch功能示例
2017/06/13 Javascript
微信小程序 动画的简单实例
2017/10/12 Javascript
vue生命周期和react生命周期对比【推荐】
2018/09/19 Javascript
解决layui表格的表头不滚动的问题
2019/09/04 Javascript
记一次react前端项目打包优化的方法
2020/03/30 Javascript
原生jQuery实现只显示年份下拉框
2020/12/24 jQuery
[02:33]2014DOTA2 TI每日综述 LGD涉险晋级DK闯入胜者组
2014/07/14 DOTA
Python实现Linux下守护进程的编写方法
2014/08/22 Python
python使用__slots__让你的代码更加节省内存
2018/09/05 Python
Python多线程处理实例详解【单进程/多进程】
2019/01/30 Python
连接pandas以及数组转pandas的方法
2019/06/28 Python
python实现打砖块游戏
2020/02/25 Python
python GUI库图形界面开发之PyQt5结合Qt Designer创建信号与槽的详细方法与实例
2020/03/08 Python
如何解决python多种版本冲突问题
2020/10/13 Python
全网最全python库selenium自动化使用详细教程
2021/01/12 Python
Linux系统下升级pip的完整步骤
2021/01/31 Python
西班牙自行车和跑步商店:Alltricks
2018/07/07 全球购物
Aurora London官网:奢华、负担得起的皮革手袋
2020/08/01 全球购物
班级德育工作实施方案
2014/02/21 职场文书
运动会闭幕式解说词
2014/02/21 职场文书
普通话宣传标语
2014/06/26 职场文书
小学德育工作总结2015
2015/05/12 职场文书
采购员工作总结范文
2015/08/12 职场文书
Go语言 详解net的tcp服务
2022/04/14 Golang
科学家研发出新型速效酶,可在 24 小时内降解塑料制品
2022/04/29 数码科技