时间:2021-07-01 10:21:17 帮助过:38人阅读
本文采取了简单的协议定制,定义了五条命令,指令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文件夹下的内容全部发送给客户端。
服务端运行结果如下:
下面是客户端的代码:
- 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的文件夹进行同步。
客户端运行结果如下:
需要注意的地方:
Client写入文件时,需要以二进制的方式打开文件,否则,在传输二进制文件时可能出现错误或导致文件损坏。
经过测试,代码可以正常的运行,文件夹同步成功,文本文件、图像和其他类型的二进制文件均可正常传输。
更多Python 基于Twisted框架的文件夹网络传输源码相关文章请关注PHP中文网!