由于文件夾可能有多層目錄,因此需要對(duì)其進(jìn)行遞歸遍歷。
本文采取了簡(jiǎn)單的協(xié)議定制,定義了五條命令,指令Head如下:
Sync:標(biāo)識(shí)開(kāi)始同步文件夾
End:標(biāo)識(shí)結(jié)束同步
File:標(biāo)識(shí)傳輸?shù)奈募ㄏ鄬?duì)路徑)
Folder:標(biāo)志文件夾(相對(duì)路徑)
None:文件內(nèi)容
每條命令以CMB_BEGIN開(kāi)始,以CMB_END結(jié)束。
客戶端需要對(duì)接收緩沖做解析,取出一條一條的指令,然后根據(jù)指令的Head做相應(yīng)的處理,比如創(chuàng)建文件夾、寫(xiě)入文件等。
下面是服務(wù)端的代碼:
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的某個(gè)信號(hào)之后(此代碼中,當(dāng)Client隨便向Server發(fā)送任何內(nèi)容都可),Server即會(huì)調(diào)用send_file_folder將sever文件夾下的內(nèi)容全部發(fā)送給客戶端。
服務(wù)端運(yùn)行結(jié)果如下:
下面是客戶端的代碼:
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() |
客戶端提取出來(lái)自Server的指令,當(dāng)提取出Sync指令時(shí),則將sourceDir目錄清空,然后根據(jù)后續(xù)的指令,跟Server的文件夾進(jìn)行同步。
客戶端運(yùn)行結(jié)果如下:
需要注意的地方:
Client寫(xiě)入文件時(shí),需要以二進(jìn)制的方式打開(kāi)文件,否則,在傳輸二進(jìn)制文件時(shí)可能出現(xiàn)錯(cuò)誤或?qū)е挛募p壞。
經(jīng)過(guò)測(cè)試,代碼可以正常的運(yùn)行,文件夾同步成功,文本文件、圖像和其他類型的二進(jìn)制文件均可正常傳輸。
原文鏈接:http://www.icodelogic.com/?p=516