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.提高处理效率 列表与队列都是有顺序的,但是他们之间有一个很大的区别 ...
随机推荐
- Java面试题复习笔记(数据库)
1.数据库分类? 关系型数据库和非关系型. 常用关系型:Myspl.Oracle.SQLServer 非关系型:Redis.Hadoop.Memcache.Mogobd 2.关系数据库三范式? 范式就 ...
- PHP 必知的 16 个编程法则
以双下划线(__)开头的方法称为魔术方法 -__construct():类的构造方法: -__destruct():类的析构方法: -__call($funName, $arguments):当访问未 ...
- 服务器与本地的控制工具unison
中文文档:https://wiki.archlinux.org/index.php/Unison_(%E7%AE%80%E4%BD%93%E4%B8%AD%E6%96%87) 下载:http://un ...
- Android 杂谈---ListView 之BaseAdapter
前言 几种适配器里面相对来说比较简单的一种适配器,在使用时需要实现几个方法,并且也需要对convertView进行优化 此篇文章以使用listView与BaseAdapter来实现表格样式的布局举例( ...
- Python学习(四十)—— Djago之认证系统
一.COOKIE 与 SESSION 概念 cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要“保持状态”,因此cookie就是在这样一个场景下诞生. cook ...
- P1341 无序字母对 欧拉回路
题目描述 给定n个各不相同的无序字母对(区分大小写,无序即字母对中的两个字母可以位置颠倒).请构造一个有n+1个字母的字符串使得每个字母对都在这个字符串中出现. 输入输出格式 输入格式: 第一行输入一 ...
- Spring Data JPA入门
1. Spring Data JPA是什么 它是Spring基于ORM框架.JPA规范封装的一套JPA应用框架,可使开发者用极简的代码即可实现对数据的访问和操作.它提供了包括增删改查等在内的常用功能, ...
- WIN10 拨号连接下 如何开启移动热点
错误提示为:我们无法设置移动热点,因为你的电脑未建立以太网,WIFI或手机网络连接. 解决方法: 1. 首先用手机或其他设备建立无线热点. 2. 电脑连接步骤1中的热点,电脑端打开移动热点. 3. ...
- django——用户认证组件
用户认证 auth模块 1 from django.contrib import auth django.contrib.auth中提供了许多方法,这里主要介绍其中的三个: 1.1 .authenti ...
- Win7 查看端口占用的进程,并根据进程id杀死进程。
搞开发的经常会有一堆的工具要使用,而很多工具都需要开启特定的端口,难免会出现端口冲突的场景,那在Win7 环境下如何排除端口被哪个进程占用了呢? 首先,通过 netstat -ano | findst ...