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 相关文章推荐
使用DataFrame删除行和列的实例讲解
Apr 08 Python
使用EduBlock轻松学习Python编程
Oct 08 Python
Python hexstring-list-str之间的转换方法
Jun 12 Python
Django框架orM与自定义SQL语句混合事务控制操作
Jun 27 Python
Python PIL图片添加字体的例子
Aug 22 Python
python加密解密库cryptography使用openSSL生成的密匙加密解密
Feb 11 Python
使用Python构造hive insert语句说明
Jun 06 Python
Python无损压缩图片的示例代码
Aug 06 Python
python安装cx_Oracle和wxPython的方法
Sep 14 Python
python中not、and和or的优先级与详细用法介绍
Nov 03 Python
python实现ping命令小程序
Dec 28 Python
python 离散点图画法的实现
Apr 01 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
高分R级DC动画剧《哈莉·奎茵》第二季正式预告首发
2020/04/09 欧美动漫
德生S2000收音机更换“钕铁硼”全频扬声器
2021/03/02 无线电
PHP--用万网的接口实现域名查询功能
2012/12/13 PHP
php递归删除指定文件夹的方法小结
2015/04/20 PHP
3种php生成唯一id的方法
2015/11/23 PHP
13个绚丽的Jquery 界面设计网站推荐
2010/09/28 Javascript
Bootstrap实现水平排列的表单
2016/07/04 Javascript
AngularJS实现根据变量改变动态加载模板的方法
2016/11/04 Javascript
jQuery代码实现实时获取时间
2017/01/29 Javascript
Vue封装Swiper实现图片轮播效果
2018/02/06 Javascript
基于Vue+element-ui 的Table二次封装的实现
2018/07/20 Javascript
JS实现面向对象继承的5种方式分析
2018/07/21 Javascript
浅谈VUE-CLI脚手架热更新太慢的原因和解决方法
2018/09/28 Javascript
基于ajax及jQuery实现局部刷新过程解析
2020/09/12 jQuery
Python3.4编程实现简单抓取爬虫功能示例
2017/09/14 Python
Python中join函数简单代码示例
2018/01/09 Python
Python实现将doc转化pdf格式文档的方法
2018/01/19 Python
python分治法求二维数组局部峰值方法
2018/04/03 Python
Python 经典面试题 21 道【不可错过】
2018/09/21 Python
学生信息管理系统Python面向对象版
2019/01/30 Python
Python3.5实现的三级菜单功能示例
2019/03/25 Python
Django实现微信小程序的登录验证功能并维护登录态
2019/07/04 Python
Python使用tkinter实现小时钟效果
2021/02/22 Python
通过canvas转换颜色为RGBA格式及性能问题的解决
2019/11/22 HTML / CSS
新加坡最早生产电动滑板车的制造商之一:FunsToTheFore
2020/09/08 全球购物
无故旷工检讨书
2014/01/26 职场文书
《开国大典》教学反思
2014/04/19 职场文书
全运会口号
2014/06/20 职场文书
春游踏青活动方案
2014/08/14 职场文书
劳动仲裁调解书
2015/05/20 职场文书
2015年公司国庆放假通知
2015/07/30 职场文书
宾馆客房管理制度
2015/08/06 职场文书
庆祝教师节主题班会
2015/08/17 职场文书
vue实现同时设置多个倒计时
2021/05/20 Vue.js
vue+elementui 实现新增和修改共用一个弹框的完整代码
2021/06/08 Vue.js
springboot如何接收application/x-www-form-urlencoded类型的请求
2021/11/02 Java/Android