转自:http://www.jb51.net/article/91435.htm
由于文件夹可能有多层目录,因此需要对其进行递归遍历。
本文采取了简单的协议定制,定义了五条命令,指令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写入文件时,需要以二进制的方式打开文件,否则,在传输二进制文件时可能出现错误或导致文件损坏。
经过测试,代码可以正常的运行,文件夹同步成功,文本文件、图像和其他类型的二进制文件均可正常传输。