已阅读:84,968 次
Python 基于Twisted框架的文件夹网络传输源码
ian | Python | 2012/03/14


由于文件夹可能有多层目录,因此需要对其进行递归遍历。

本文采取了简单的协议定制,定义了五条命令,指令Head如下:
Sync:标识开始同步文件夹
End:标识结束同步
File:标识传输的文件名(相对路径)
Folder:标志文件夹(相对路径)
None:文件内容

每条命令以CMB_BEGIN开始,以CMB_END结束。

客户端需要对接收缓冲做解析,取出一条一条的指令,然后根据指令的Head做相应的处理,比如创建文件夹、写入文件等。

下面是服务端的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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文件夹下的内容全部发送给客户端。

服务端运行结果如下:

下面是客户端的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
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写入文件时,需要以二进制的方式打开文件,否则,在传输二进制文件时可能出现错误或导致文件损坏。

经过测试,代码可以正常的运行,文件夹同步成功,文本文件、图像和其他类型的二进制文件均可正常传输。

原创文章,转载请注明:转载自ian的个人博客[http://www.icodelogic.com]
本文链接地址: http://www.icodelogic.com/?p=516

tags:

没有评论

发表评论

你需要先 登录 才能回复