Python3学习之路~8.4 利用socket实现文件传送+MD5校验
利用socket实现文件传送,大约分为如下几步:
1.读取文件名
2.检测文件是否存在
3.打开文件(别忘了最后关闭文件)
4.检测文件大小
5.发送文件大小给客户端
6.等客户端确认
7.开始边读边发数据
8.md5验证
实例1:实现步骤1-7
运行代码
#Author:Zheng Na #ftp服务端
import socket
import os server = socket.socket() server.bind(('localhost',6969)) server.listen() while True:
print("等待新客户端连接")
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() # 1.读取文件名
print("文件名:",filename)
if os.path.isfile(filename): # 2.判断文件是否存在
f = open(filename,'rb') # 3.打开文件
file_size = os.stat(filename).st_size # 4.检测文件大小
conn.send(str(file_size).encode()) # 5.发送文件大小给客户端
print("等待客户ack应答...")
client_final_ack = conn.recv(1024) # 6.等待客户端确认
print("客户应答:", client_final_ack.decode("UTF-8"))
for line in f: # 7.开始边读边发数据
conn.send(line)
f.close() # 关闭文件
print("send done") server.close()
ftp_socket_server1_simple.py
#Author:Zheng Na #ftp客户端
import socket client = socket.socket() client.connect(('localhost',6969)) while True:
cmd = input(">>: ").strip()
if len(cmd) == 0: continue
if cmd.startswith("get"):
client.send(cmd.encode())
server_response = client.recv(1024)
print("server response: ",server_response)
client.send(b'ready to recv file')
file_total_size = int(server_response.decode())
received_size = 0
filename = cmd.split()[1]
f = open(filename+'.new','wb')
while received_size < file_total_size:
data = client.recv(1024)
received_size += len(data)
f.write(data)
# print(file_total_size,received_size)
else:
print("file recv done",file_total_size,received_size)
f.close() client.close()
ftp_socket_client1_simple.py
输出结果
[root@hadoop my-test-files]# python3 ftp_socket_server1_simple.py
等待新客户端连接
new conn: ('127.0.0.1', 34556)
等待新指令
文件名: test.txt
等待客户ack应答...
客户应答: ready to recv file
send done
等待新指令 [root@hadoop my-test-files]# python3 ftp_socket_client1_simple.py
>>: get test.txt
server response: b''
file recv done 5028317 5028317
>>: [root@hadoop my-test-files]# ll test*
-rw-r--r-- 1 root root 5028317 12月 5 18:28 test.txt
-rw-r--r-- 1 root root 5028317 12月 6 16:16 test.txt.new
[root@hadoop my-test-files]# diff test.txt test.txt.new # 比较两个文件是否相同
[root@hadoop my-test-files]#
输出结果
实例2:实现步骤8:md5验证
接下来,我们来给传送的文件进行MD5验证。
思路:
在服务端对要发送的文件进行MD5加密,得到一个16进制格式的hash1,发送给客户端;
在客户端对接收到的文件进行MD5加密,得到一个hash2,并与hash1进行对比,如果相同,说明接收到的文件与服务器文件一致。
由于文件比较大,可以打开文件后一行一行的进行md5加密,这样操作与整个文件一起加密效果是一致的。
比如下面两段代码效果是一致的:
# 代码1
import hashlib
hash = hashlib.md5()
hash.update(b'Hello ')
hash.update(b'World')
print(hash.hexdigest()) # b10a8db164e0754105b7a99be72e3fe5 # 代码2
import hashlib
hash = hashlib.md5()
hash.update(b'Hello World')
print(hash.hexdigest()) # b10a8db164e0754105b7a99be72e3fe5
md5关键代码
另外,由于服务端先发送了文件,再发送md5,为了防止两次send之间的粘包,我们可以在两次send之间加一段 客户确认 的代码,但是这次我们不这么做:
由于在客户端接收文件时是循环接收,我们可以在接收文件前,加一个判断,判断最后一次接收文件的大小,如果小于1024字节,那么最后一次只接收文件最后剩下的部分。
这样就可以保证最后接收的文件正好是发送文件的大小,从而不会导致粘包。
运行代码
#Author:Zheng Na #ftp服务端
import socket
import os
import hashlib server = socket.socket() server.bind(('localhost',6969)) server.listen() while True:
print("等待新客户端连接")
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() # 1.读取文件名
print("文件名:",filename)
if os.path.isfile(filename): # 2.判断文件是否存在
f = open(filename,'rb') # 3.打开文件
file_size = os.stat(filename).st_size # 4.检测文件大小
conn.send(str(file_size).encode()) # 5.发送文件大小给客户端
print("等待客户ack应答...")
client_final_ack = conn.recv(1024) # 6.等待客户端确认
print("客户应答:", client_final_ack.decode("UTF-8"))
m = hashlib.md5() # 8.1 md5
for line in f: # 7.开始边读边发数据
m.update(line) # 8.2 md5
conn.send(line) server_file_md5 = m.hexdigest() # 8.3 md5
print("server file md5: ",server_file_md5)
conn.send(server_file_md5.encode()) # 8.4 md5 f.close() # 关闭文件
print("send done") server.close()
ftp_socket_server2_md5.py
#Author:Zheng Na #ftp客户端
import socket
import hashlib client = socket.socket() client.connect(('localhost',6969)) while True:
cmd = input(">>: ").strip()
if len(cmd) == 0: continue
if cmd.startswith("get"):
client.send(cmd.encode())
server_response = client.recv(1024)
print("server response: ",server_response)
client.send(b'ready to recv file')
file_total_size = int(server_response.decode())
received_size = 0
filename = cmd.split()[1]
f = open(filename+'.new','wb')
m = hashlib.md5()
while received_size < file_total_size: # 接收文件,防止粘包
if file_total_size - received_size > 1024: # 要收的不止一次
size = 1024
else:# 最后一次了,剩多少收多少
size = file_total_size -received_size
print("last receive:",size) data = client.recv(size)
received_size += len(data)
m.update(data)
f.write(data)
# print(file_total_size,received_size)
else:
client_file_md5 = m.hexdigest()
print("file recv done",file_total_size,received_size)
f.close() server_file_md5 = client.recv(1024).decode()
print("server file md5: ",server_file_md5)
print("client file md5: ",client_file_md5)
if server_file_md5 == client_file_md5:
print("server file md5 and client file md5 are same")
else:
print("server file md5 and client file md5 are different") client.close()
ftp_socket_client2_md5.py
注意:使用md5加密,运行结果会变慢。
输出结果
[root@hadoop my-test-files]# python3 ftp_socket_server2_md5.py
等待新客户端连接
new conn: ('127.0.0.1', 34566)
等待新指令
文件名: test.txt
等待客户ack应答...
客户应答: ready to recv file
server file md5: 01e16e921c663c9e90246ddb7d9a746f
send done
等待新指令 [root@hadoop my-test-files]# python3 ftp_socket_client2_md5.py
>>: get test.txt
server response: b''
last receive: 335
file recv done 5028317 5028317
server file md5: 01e16e921c663c9e90246ddb7d9a746f
client file md5: 01e16e921c663c9e90246ddb7d9a746f
server file md5 and client file md5 are same
>>: [root@hadoop my-test-files]# ll test*
-rw-r--r-- 1 root root 5028317 12月 5 18:28 test.txt
-rw-r--r-- 1 root root 5028317 12月 6 17:44 test.txt.new
[root@hadoop my-test-files]# diff test.txt test.txt.new
[root@hadoop my-test-files]#
输出结果
Python3学习之路~8.4 利用socket实现文件传送+MD5校验的更多相关文章
- Python3学习之路~0 目录
目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...
- Python3学习之路~8.2 socket简单实例 实现ssh 发送大量数据
实例1: 利用socket模拟客户端和服务器端各自收发一次数据: #Author:Zheng Na # 客户端 import socket # 声明socket类型,同时生成socket连接对象 cl ...
- Python socket文件传送md5校验
soket_server import socket,os,hashlib server = socket.socket() server.bind(('0.0.0.0',9999)) server. ...
- Python3学习之路~8.1 socket概念及参数介绍
一 socket介绍 TCP/IP 基于TCP/IP协议栈的网络编程是最基本的网络编程方式,主要是使用各种编程语言,利用操作系统提供的套接字网络编程接口,直接开发各种网络应用程序. socket概念 ...
- Python3学习之路~8.3 socket 服务端与客户端
通过8.2的实例1-6,我们可以总结出来,socket的服务端和客户端的一般建立步骤: 服务端 步骤:1创建实例,2绑定,3监听,4阻塞,5发送&接收数据,6关闭. #Author:Zheng ...
- Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现
作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...
- Python3学习之路~8.5 SocketServer实现多并发
前面几节我们写的socket都只能实现服务端与一个客户端通信,并不能实现服务端与多客户端同时通信.接下来我们就来学习一下如何实现服务端同时与多个客户端通信,即并发. Socket Server soc ...
- Python3学习之路~10.2 协程、Greenlet、Gevent
一 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ...
- Python3学习之路~9.4 队列、生产者消费者模型
一 队列queue 当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用. 队列的作用:1.解耦,使程序直接实现松耦合 2.提高处理效率 列表与队列都是有顺序的,但是他们之间有一个很大的区别 ...
随机推荐
- PHP迭代器:Iterator和IteratorAggregate
使用迭代模式遍历所有的对象的时候,都必须实现Traversable(遍历)接口.但是Traversable是一个内部的类,只有用c语言编写的类才可以实现Traversable实现.如果我们在自定义的 ...
- Android Studio打开项目,停在gradle的解决方案
之所以停留,是因为打开项目时,Android Studio解析项目使用的gradle,并下载对应版本的gradle,但是由于下载gradle的服务器在国外,这个下载速度非常不稳定,从而导致停留在这一步 ...
- scrapy相关 通过设置 FEED_EXPORT_ENCODING 解决 unicode 中文写入json文件出现`\uXXXX`
0.问题现象 爬取 item: 2017-10-16 18:17:33 [scrapy.core.scraper] DEBUG: Scraped from <200 https://www.hu ...
- Swagger-概述
前言 Swagger 是一款RESTFUL接口的文档在线自动生成+功能测试功能软件.本文简单介绍了在项目中集成swagger的方法和一些常见问题.如果想深入分析项目源码,了解更多内容,见参考资料. S ...
- 辅助排序和Mapreduce整体流程
一.辅助排序 需求:先有一个订单数据文件,包含了订单id.商品id.商品价格,要求将订单id正序,商品价格倒序,且生成结果文件个数为订单id的数量,每个结果文件中只要一条该订单最贵商品的数据. 思路: ...
- 理解ActivityManagerService
--摘自<Android进阶解密> *AMS家族* 1.Android 7.0的AMS家族 2.AMP和AMS进行通信 3.(Android 7.0)AMP是AMN的内部类,它们都实现了I ...
- GG的文化课
attack大神退役后,我连文化课都被吊打了 attack:我要回来虐你们了 attack:怎么感觉能裸分清北呢 attack:我稳了 attack:你们个菜鸡,连bed和bad怎么读都不知道
- XVIII Open Cup named after E.V. Pankratiev. Ukrainian Grand Prix
A. Accommodation Plan 对于已知的$K$个点,离它们距离都不超过$L$的点在树上是一个连通块,考虑在每种方案对应的离$1$最近的点统计. 即对于每个点$x$,统计离它距离不超过$L ...
- 给出两个单词word1和word2,写一个函数计算出将word1 转换为word2的最少操作次数。
问题: 给出两个单词word1和word2,写一个函数计算出将word1 转换为word2的最少操作次数. 你总共三种操作方法: 1.插入一个字符 2.删除一个字符 3.替换一个字符 格式: 输入行输 ...
- Lock锁方式解决线程安全问题
在JDK5.0之后新增加了一种更强大的线程同步机制---通过显示定义同步锁来实现线程同步解决线程安全问题.同步锁使用Lock对象充当. java.util.concurrent.locks.lock接 ...