socket传送文件
一、文件传送步骤
我们要利用socket来实现下载一个文件,该如何操作呢?
服务端:
- 读取文件名
- 判断文件是否存在
- 检测文件大小(用于和客户端对比判断文件是否传送完毕)
- 发送文件大小给客户端
- 等待客户端确认(防止粘包)
- 打开文件
- 边读边发送数据
- md5验证
客户端:
- 发送命令
- 接收文件大小
- 返回确认
- 获取文件名
- 对比文件大小
- 写入文件
二、功能实现(ftp下载功能)
服务端:
# -*- coding: UTF-8 -*- import os import socket # TCP/IP协议, tcp ,如果不填写就是默认这个 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('localhost', 9999)) server.listen() while True: # 可以接受多个客户端 conn, addr = server.accept() print('new conn', addr) while True: cmd_res = conn.recv(1024) if not cmd_res: # 防止当接受的客户端数据为空时,程序卡掉 print('client has lost...') break else: # 获取命令和文件名 cmd, filename = cmd_res.decode().split() print(cmd, filename) if os.path.isfile(filename): # 判断文件是否存在 # 文件大小 file_size = os.stat(filename).st_size # 发送文件大小 conn.send(str(file_size).encode(encoding='utf-8')) # 等待客户端确认 conn.recv(1024) # 打开文件 f = open(filename, 'rb') for line in f: conn.send(line) print('sending') f.close()
客户端:
# -*- coding: UTF-8 -*- import socket client = socket.socket() client.connect(('localhost', 9999)) while True: cmd = input('>>:').strip() # 判断是否发送空数据,如果是就重新发送 if len(cmd) == 0: continue else: client.send(cmd.encode('utf-8')) # 获取服务端发送的文件大小 size = client.recv(1024) total_file_size = int(size.decode()) # 返回确认 client.send(b'file size received') filename = cmd.split()[1] print(filename) received_size = 0 # 写入文件 f = open(filename + '.new', 'w', encoding='utf-8') while received_size < total_file_size: r_data = client.recv(1024) received_size += len(r_data) f.write(r_data.decode() + '\n') else: print('file sizes', total_file_size, received_size) print('receive finished') f.close()
有些问题 替换一些内容
f = open(filename + '.new', 'wb')
f.write(r_data)
这个程序有缺陷,首先目前只能读取本文件夹下的文件,新生成的文件没有中文乱码问题,ok...
三、md5验证文件
加个md5来验证文件是否一致
服务端:
# -*- coding: UTF-8 -*- import os import socket import hashlib # TCP/IP协议, tcp ,如果不填写就是默认这个 server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(('localhost', 9999)) server.listen() while True: # 可以接受多个客户端 conn, addr = server.accept() print('new conn', addr) while True: cmd_res = conn.recv(1024) if not cmd_res: # 防止当接受的客户端数据为空时,程序卡掉 print('client has lost...') break else: # md5 m = hashlib.md5() # 获取命令和文件名 cmd, filename = cmd_res.decode().split() print(cmd, filename) if os.path.isfile(filename): # 判断文件是否存在 # 文件大小 file_size = os.stat(filename).st_size print(file_size) # 发送文件大小 conn.send(str(file_size).encode(encoding='utf-8')) # 等待客户端确认 conn.recv(1024) # 打开文件 f = open(filename, 'rb') for line in f: m.update(line) # m.update('abc') m.update('123') # 其实和m.update('abc123') 结果一下 conn.send(line) f.close() print('send done') # 发送md5信息 conn.send(m.hexdigest().encode('utf-8'))
客户端:
# -*- coding: UTF-8 -*- import socket import hashlib client = socket.socket() client.connect(('localhost', 9999)) while True: cmd = input('>>:').strip() # 判断是否发送空数据,如果是就重新发送 if len(cmd) == 0: continue else: client.send(cmd.encode('utf-8')) # 获取服务端发送的文件大小 f_size = client.recv(1024) total_file_size = int(f_size.decode()) # 返回确认 client.send(b'file size received') filename = cmd.split()[1] print(filename) received_size = 0 # md5 m = hashlib.md5() # 写入文件 f = open(filename + '.new', 'wb') # 新生成的文件也正常显示 while received_size < total_file_size: if total_file_size - received_size > 1024: # 以此来控制只收文件的内容,不会粘包md5的内容 size = 1024 else: size = total_file_size - received_size r_data = client.recv(size) received_size += len(r_data) m.update(r_data) f.write(r_data) # print(r_data.decode()) # print('file sizes', total_file_size, received_size) else: print('file sizes', total_file_size, received_size) server_md5 = client.recv(1024).decode() client_md5 = m.hexdigest() print(server_md5) print(client_md5) print('receive finished') f.close()
结果:
结果看上去没有问题了,新文件也能生成,并且有内容