利用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校验的更多相关文章

  1. Python3学习之路~0 目录

    目录 Python3学习之路~2.1 列表.元组操作 Python3学习之路~2.2 简单的购物车程序 Python3学习之路~2.3 字符串操作 Python3学习之路~2.4 字典操作 Pytho ...

  2. Python3学习之路~8.2 socket简单实例 实现ssh 发送大量数据

    实例1: 利用socket模拟客户端和服务器端各自收发一次数据: #Author:Zheng Na # 客户端 import socket # 声明socket类型,同时生成socket连接对象 cl ...

  3. Python socket文件传送md5校验

    soket_server import socket,os,hashlib server = socket.socket() server.bind(('0.0.0.0',9999)) server. ...

  4. Python3学习之路~8.1 socket概念及参数介绍

    一 socket介绍 TCP/IP 基于TCP/IP协议栈的网络编程是最基本的网络编程方式,主要是使用各种编程语言,利用操作系统提供的套接字网络编程接口,直接开发各种网络应用程序. socket概念 ...

  5. Python3学习之路~8.3 socket 服务端与客户端

    通过8.2的实例1-6,我们可以总结出来,socket的服务端和客户端的一般建立步骤: 服务端 步骤:1创建实例,2绑定,3监听,4阻塞,5发送&接收数据,6关闭. #Author:Zheng ...

  6. Python3学习之路~8.6 开发一个支持多用户在线的FTP程序-代码实现

    作业: 开发一个支持多用户在线的FTP程序 要求: 用户加密认证 允许同时多用户登录 每个用户有自己的家目录 ,且只能访问自己的家目录 对用户进行磁盘配额,每个用户的可用空间不同 允许用户在ftp s ...

  7. Python3学习之路~8.5 SocketServer实现多并发

    前面几节我们写的socket都只能实现服务端与一个客户端通信,并不能实现服务端与多客户端同时通信.接下来我们就来学习一下如何实现服务端同时与多个客户端通信,即并发. Socket Server soc ...

  8. Python3学习之路~10.2 协程、Greenlet、Gevent

    一 协程 协程,又称微线程,纤程.英文名Coroutine.一句话说明什么是线程:协程是一种用户态的轻量级线程. 协程拥有自己的寄存器上下文和栈.协程调度切换时,将寄存器上下文和栈保存到其他地方,在切 ...

  9. Python3学习之路~9.4 队列、生产者消费者模型

    一 队列queue 当必须在多个线程之间安全地交换信息时,队列在线程编程中特别有用. 队列的作用:1.解耦,使程序直接实现松耦合 2.提高处理效率 列表与队列都是有顺序的,但是他们之间有一个很大的区别 ...

随机推荐

  1. FM算法(二):工程实现

    主要内容: 实现方法 Python实现FM算法 libFM   一.实现方法 1.FM模型函数 变换为线性复杂度的计算公式: 2.FM优化目标 根据不同的应用,FM可以采用不同的损失函数loss fu ...

  2. Mysql-innoDB存储引擎(事物,锁,MVCC)

    innoDB的特性: 从图中由上至下红色框中的信息是:基于主键的聚集索引 ,数据缓存,外键支持(逻辑上建立外键),行级别锁,MVCC多版本控制,事务支持.这些也是InnoDB最重要的特性. 事务: 数 ...

  3. laravel 黑名单功能实现

    创建黑名单表迁移:php artisan make:model Models/BlackFeeds -m    (生成模型和迁移文件) 迁移文件中创建如下字段: public function up( ...

  4. mac os安装shell man中文帮助工具(manpages-zh),即man命令显示中文帮助文档

    一.从官网(http://pkgs.fedoraproject.org/repo/pkgs/man-pages-zh-CN)下载安装包:或者从开源代码(https://github.com/man-p ...

  5. type=file的inpu美化,自定义上传按钮样式

    <div class="div1"> <div class="div2">点击上传</div> <input type ...

  6. 20165220 mybash

    使用fork,exec,wait实现mybash - 写出伪代码,产品代码和测试代码 - 发表知识理解,实现过程和问题解决的博客(包含代码托管链接) 1.fork 功能:创建一个新的进程 一个现存进程 ...

  7. js单元测试

    最近研究了js的单元测试,分享一下心得. 说起单元测试以前还真是不太了解,这次索性了解一番,测试有很多包含单元测试,性能测试,安全测试和功能测试等几方面,本次只介绍一下单元测试. 前端进行单元测试主要 ...

  8. windows应用程序框架及实例

    应用程序框架:同一类型应用程序的结构大致相同,并有很多相同的源代码,因此可以通过一个应用程序框架AFX(Application FrameWorks)编写同一类型应用程序的通用源代码. 主要向导: D ...

  9. xls 编码 utf-8

    直接用 Excel 打开 UTF-8 编码的 CSV 文件会导致汉字部分出现乱码.原因是 Excel 以 ANSI 格式打开,不会做编码识别. ==打开 UTF-8 编码的 CSV 文件的方法:1) ...

  10. golang str 首字母大写

    首字母大写 //如果是小写字母, 则变换为大写字母 func strFirstToUpper(str string) string { if len(str) < 1 { return &quo ...