网络编程基础【day09】:socket实现文件发送(六)
本节内容
1、概述
2、文件下载实现
3、MD5值校验
一、概述
我们如何利用socket去下载一个文件,整体思路是这样的:
- 读取文件名
- 检测文件是否存在
- 打开文件
- 检测文件大小
- 发送文件大小给客户端
- 等客户确认
- 开始边读边发数据
- 发送md5值给客户端校验
友情提示:以下代码都是在Linux系统,并且是python3换将下实验的。
二、文件下载实现
2.1、服务端代码
逻辑:获取命令和文件名->判断文件是否存在->打开文件->获取文件大小->发送文件大小给客户端->等待客户端确认->边读边发
|
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
|
import hashlibimport socket,osserver = socket.socket()server.bind(("localhost",9999))server.listen()while True: conn,addr = server.accept() print("new conn:",addr) while True: print("等待新指令") data = conn.recv(1024) if not data: print("客户端已断开") break cmd,filename = data.decode().split() #接收客户端发过来的命令和文件名 print(filename) if os.path.isfile(filename): #判断文件是否存在 # m = hashlib.md5() with open(filename,"rb") as f: file_size = os.stat(filename).st_size #获取文件大小 conn.send( str(file_size).encode() ) #发送文件大小 conn.recv(1024) for line in f: #m.update(line) conn.send(line) #边读边发给客户端 #print("file md5",m.hexdigest()) print("send done")server.close() |
2.2、客户端代码
逻辑:判断是否是下载命令(get) ->发送下载命令和文件名 ->获取文件大小->发送确认信息->判断时候已经全部接收
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
import socketclient = socket.socket()client.connect(("localhost",9999))while True: cmd = input(">>>:").strip() if len(cmd) == 0:continue if cmd.startswith("get"): client.send(cmd.encode()) #发送下载命令和文件名 server_respose = client.recv(1024) #接收文件大小 print("server response:",server_respose) client.send("ready to recv file".encode()) #发送确认信息 file_total_size = int(server_respose.decode()) revived_size = 0 #初始化接收大小 filename = cmd.split()[1] #获取文件名 with open(filename + ".new","wb") as f: while revived_size < file_total_size: #判断接收大小和文件大小比较 data = client.recv(1024) revived_size += len(data) #接收大小 f.write(data) #写入文件 else: print(file_total_size,revived_size) print("file recv done")client.close() |
三、MD5值校验
说明:上面只提到了怎么传输,我们在概述里面也提到了最后要用MD5值做校验,但是很显然没看到,下面我们就来说说怎么用MD5值做比较
3.1、服务端
说明:生成md5的对象->计算MD5值->生成16进制的形式->编码后发送给客户端
①代码
|
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
|
import hashlibimport socket,osserver = socket.socket()server.bind(("localhost",9999))server.listen()while True: conn,addr = server.accept() print("new conn:",addr) while True: print("等待新指令") data = conn.recv(1024) if not data: print("客户端已断开") break cmd,filename = data.decode().split() print(filename) if os.path.isfile(filename): m = hashlib.md5() #生成MD5的对象 with open(filename,"rb") as f: file_size = os.stat(filename).st_size conn.send( str(file_size).encode() ) #send file size conn.recv(1024) for line in f: m.update(line) #计算md5值 conn.send(line) print("file md5",m.hexdigest()) conn.recv(1024) #等待客户确认发送MD5值 conn.send(m.hexdigest().encode()) #生成MD5值并且发送给客户端 print("send done")server.close() |
②改动的地方

3.2、客户端
说明:生成MD5值->计算接收的数据的MD5值->生成接收数据的MD5值16进制的形式->发送接收MD5值确认信息->接收客户端的MD5值->客户端和服务端的MD5值做比较
①代码
|
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
|
# __auther__ == zhangqigaoimport socket,hashlibclient = socket.socket()client.connect(("localhost",9999))while True: cmd = input(">>>:").strip() if len(cmd) == 0:continue if cmd.startswith("get"): client.send(cmd.encode()) server_respose = client.recv(1024) print("server response:",server_respose) client.send("ready to recv file".encode()) file_total_size = int(server_respose.decode()) revived_size = 0 filename = cmd.split()[1] m = hashlib.md5() #生成MD5对象 with open(filename + ".new","wb") as f: while revived_size < file_total_size: data = client.recv(1024) revived_size += len(data) m.update(data) #计算数据接收的MD5值 f.write(data) else: print(file_total_size,revived_size) client_md5_vaule = m.hexdigest() #生成接收数据的MD5值16进制形式 client.send("ready to recv file md5 value".encode()) server_md5_value = client.recv(1024) #接收客户端的MD5值 if client_md5_vaule == server_md5_value.decode(): #客户端和服务端的MD5值做比较 print("file recv done") else: print(client_md5_vaule,server_md5_value.decode())client.close() |
②改动地方

总结:
- 上传和下载都是以客户端或者服务端加载文件,然后另外一边接收再写入文件。
- 解决粘包问题,在接收数据大小后需要等待确认信息。
- 看文件能都上传和下载,应该用MD5值去校验。
- 创建一个无限大的文件,请用:dd if=/dev/sda1 of=文件名,比如创建test.txt,则:dd if=/dev/sda1 of=test.txt
- 获取一个文件的大小:os.stat(文件名).st_size
作者:罗阿红
出处:http://www.cnblogs.com/luoahong/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接。

浙公网安备 33010602011771号