python (大文件下载及进度条展示) 验证客户端链接的合法性,socketserver
##########总结###########
文件校验加进度条显示
####server
import os
import json
import socket
import struct
import hashlib sk = socket.socket()
sk.bind(('127.0.0.1', 9000))
sk.listen()
conn, addr = sk.accept()
filename = 'mysql-5.6.42-winx64.zip' # 文件名
absolute_path = os.path.join('D:\老男孩老师笔记\第二阶段共享', filename) # 文件绝对路径
buffer_size = 1024 * 1024 # 缓冲大小,这里表示1MB md5obj = hashlib.md5()
with open(absolute_path, 'rb') as f:
while True:
content = f.read(buffer_size) # 每次读取指定字节
if content:
md5obj.update(content)
else:
break # 当内容为空时,终止循环
md5 = md5obj.hexdigest()#打印出16进制的md5值
print(md5) # 打印md5值 dic = {'filename': filename,
'filename_md5': str(md5), 'buffer_size': buffer_size,
'filesize': os.path.getsize(absolute_path)}
str_dic = json.dumps(dic).encode('utf-8')
len_dic = len(str_dic)
length = struct.pack('i', len_dic)
conn.send(length) # dic的长度
conn.send(str_dic) # dic
with open(absolute_path, 'rb') as f: # 文件
while dic['filesize']:
content = f.read(dic['buffer_size'])
conn.send(content)
dic['filesize'] -= len(content)
'''
这里不能减等4096,因为文件,最后可能只有3字节。
要根据读取的长度len(content),来计算才是合理的。
'''
conn.close()
###############
1cb1926af121c5c1b52a1ec13314805b
####client
import json
import struct
import socket
import sys
import time
import hashlib
import os
def processBar(num, total): # 进度条 [接收大小,文件大小]
rate = num / total
rate_num = int(rate * 100)
if rate_num == 100:
r = '\r%s>%d%%\n' % ('=' * rate_num, rate_num,)
else:
r = '\r%s>%d%%' % ('=' * rate_num, rate_num,)
sys.stdout.write(r)
sys.stdout.flush start_time = time.time() # 开始时间
sk = socket.socket()
sk.connect(('127.0.0.1', 9000)) dic_len = sk.recv(4)
dic_len = struct.unpack('i', dic_len)[0]#查看长度
str_dic = sk.recv(dic_len).decode('utf-8')
dic = json.loads(str_dic) md5 = hashlib.md5()
with open(dic['filename'], 'wb') as f: # 使用wb更严谨一些,虽然可以使用ab
content_size = 0
while True:
content = sk.recv(dic['buffer_size']) # 接收指定大小
f.write(content) # 写入文件
content_size += len(content) # 接收大小
md5.update(content) # 摘要 processBar(content_size, dic['filesize']) # 执行进度条函数 [接收大小,文件大小]
if content_size == dic['filesize']: break # 当接收的等于文件大小时,终止循环 md5 = md5.hexdigest()
print(md5) # 打印md5值
if dic['filename_md5'] == str(md5):
print(('md5校验正确--下载成功'))
else:
print('文件验证失败')
os.remove(dic['filename']) # 删除文件
sk.close() # 关闭连接
end_time = time.time() # 结束时间
print('本次下载花费了{}秒'.format(end_time - start_time))
############
====================================================================================================>100%
1cb1926af121c5c1b52a1ec13314805b
md5校验正确--下载成功
本次下载花费了18.044031858444214秒
####验证合法性
使用hashlib.md5 加密

为什么要随机字符串,是为了防止客户端的数据被窃取
生成随机的bytes类型数据,它是解不出来的
import os
print(os.urandom(32))
执行输出:
b'PO\xca8\xc8\xf3\xa0\xb5,\xdd\xb8K \xa8D\x9cN"\x82\x03\x86g\x18e\xa7\x97\xa77\xb9\xa5VA'
###server
import os
import socket
import hashlib secret_key = '老衲洗头用飘柔' # 加密key sk = socket.socket()
sk.bind(('127.0.0.1',9000))
sk.listen()
while True:
try:
conn,addr = sk.accept()
random_bytes = os.urandom(32) # 随即产生32个字节的字符串,返回bytes
conn.send(random_bytes) # 发送随机加密key
md5 = hashlib.md5(secret_key.encode('utf-8')) # 使用secret_key作为加密盐
md5.update(random_bytes) #得到MD5消息摘要
ret = md5.hexdigest() #以16进制返回消息摘要,它是一个32位长度的字符串
msg = conn.recv(1024).decode('utf-8') # 接收的信息解码
if msg == ret:print('是合法的客户端') # 如果接收的摘要和本机计算的摘要一致,就说明是合法的
else:conn.close() # 关闭连接
finally: # 无论如何,都执行下面的代码
sk.close() # 关闭连接
break
###client
import socket
import hashlib
secret_key = '老衲洗头用飘柔' # 加密key
sk = socket.socket()
sk.connect(('127.0.0.1',9000)) urandom = sk.recv(32) # 接收32字节,也就是os.urandom的返回值
md5_obj = hashlib.md5(secret_key.encode('utf-8')) # 使用加密盐加密
md5_obj.update(urandom)
sk.send(md5_obj.hexdigest().encode('utf-8')) # 发送md5摘要
print('-----')
sk.close() # 关闭连接
先执行server.py,再执行client.py
client输出:-----
server输出:是合法的客户端
socketserver
SocketServer内部使用 IO多路复用 以及 “多线程” 和 “多进程” ,从而实现并发处理多个客户端请求的Socket服务端。即:每个客户端请求连接到服务器时,Socket服务端都会在服务器是创建一个“线程”或者“进 程” 专门负责处理当前客户端的所有请求。

它能实现多个客户端,同时连接,它继承了socket
####server
import socketserver
class MyServer(socketserver.BaseRequestHandler):
def handle(self):
print(self.request)
self.request.send(b'hello') # 跟所有的client打招呼
print(self.request.recv(1024)) # 接收客户端的信息 server = socketserver.ThreadingTCPServer(('127.0.0.1',9000),MyServer)
server.serve_forever()
#######client
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',9000))
print(sk.recv(1024))
inp = input('>>>').encode('utf-8')
sk.send(inp)
sk.close()
client输出:
b'hello'
>>>hi
server输出:
<socket.socket fd=316, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('127.0.0.1', 9000), raddr=('127.0.0.1', 49176)>
b'hi'
开多个客户端,也可以执行


########自己写一个socketserver
###server
import socket
from threading import Thread
class MySocket:
#init方法,将ip和端口封装到了self里面,并且实例化了一个socket对象
def __init__(self,server_addr): self.server_addr = server_addr
self.socket = socket.socket() #绑定了ip地址和端口,监听,执行了建立连接的方法
def serve_forever(self):
self.socket.bind(self.server_addr)
self.socket.listen(5)
self.build_connect()
#建立连接,将建立连接的过程循环起来,因为我们每次建立连接都需要开一个线程带走这个连接,去通过这个连接收发消息.
def build_connect(self): while 1:
#让主线程代码循环起来,要让accept方法和handle方法要异步起来,不然建立连接的这个循环无法循环起来,因为进入handle之后就出不来了,异步你会想到什么,并发,多进程或者多线程,多进程不合适,所以用多线程,每一个conn,一个线程
conn,addr = self.socket.accept()
# self.handle(conn)
#开线程处理conn,一个线程一个conn,
t = Thread(target=self.handle,args=(conn,))
t.start()
#收发消息的内容,每个线程都需要执行一下handle方法,将conn作为参数传给handle方法
def handle(self,conn):
while 1:
from_client_msg = conn.recv(1024).decode('utf-8')
print('来自客户的消息>>>>',from_client_msg) to_client_msg = input('宝宝说>>>>')
conn.send(to_client_msg.encode('utf-8')) if __name__ == '__main__':
ip_port = ('127.0.0.1',8001)
server = MySocket(ip_port)
server.serve_forever()
###client 可实现多个客户端 同时和一个server应对
import socket
client = socket.socket()
client.connect(('127.0.0.1',8001))
while 1:
to_server_msg = input('给宝宝的消息>>>')
client.send(to_server_msg.encode('utf-8')) from_server_msg = client.recv(1024).decode('utf-8')
print('来自宝宝的消息:',from_server_msg)
python (大文件下载及进度条展示) 验证客户端链接的合法性,socketserver的更多相关文章
- python 全栈开发,Day36(作业讲解(大文件下载以及进度条展示),socket的更多方法介绍,验证客户端链接的合法性hmac,socketserver)
先来回顾一下昨天的内容 黏包现象粘包现象的成因 : tcp协议的特点 面向流的 为了保证可靠传输 所以有很多优化的机制 无边界 所有在连接建立的基础上传递的数据之间没有界限 收发消息很有可能不完全相 ...
- 036_python的大文件下载以及进度条展示
复习 1.黏包现象 粘包现象的成因: tcp协议的特点,面向流的,为了保证可靠传输,所以有很多优化的机制. 无边界 所有在连接建立的基础上传递的数据之间没有界限. 收发消息很有可能不完全相等. 缓存机 ...
- Python之socketserver模块和验证客户端链接的合法性
验证客户端链接的合法性 分布式系统中实现一个简单的客户端链接认证功能 #_*_coding:utf-8_*_ from socket import * import hmac,os secret_ke ...
- python:验证客户端链接的合法性与socketserver
一.验证客户端链接的合法性 from socket import * import hmac,os secret_key=b'linhaifeng bang bang bang' def conn_a ...
- python网络编程之验证客户端链接的合法性
六.socket的更多方法介绍 服务端套接字函数s.bind() 绑定(主机,端口号)到套接字s.listen() 开始TCP监听s.accept() b被动接收TCP客户的连接,(阻塞式)等待连接的 ...
- socketv 验证客户端链接的合法性,socketserver
补充: send()与sendall() 在python socket编程中,有两个发送TCP的函数,send()与sendall(),区别如下: socket.send(string[, flags ...
- socketv 验证客户端链接的合法性
一 .socketv 验证客户端链接的合法性 send()与sendall() 验证客户端 加密验证 如果你想在分布式系统中实现一个简单的客户端链接认证功能,又不像SSL那么复杂,那么利用hmac+加 ...
- 一个简单、易用的Python命令行(terminal)进度条库
eprogress 是一个简单.易用的基于Python3的命令行(terminal)进度条库,可以自由选择使用单行显示.多行显示进度条或转圈加载方式,也可以混合使用. 示例 单行进度条 多行进度条 圆 ...
- Asp.Net上传大文件带进度条swfupload
Asp.Net基于swfupload上传大文件带进度条百分比显示,漂亮大气上档次,大文件无压力,先看效果 一.上传效果图 1.上传前界面:图片不喜欢可以自己换 2.上传中界面:百分比显示 3.上传后返 ...
随机推荐
- MySQL 同一台服务器同步数据
声明:我配置出来的slave_io_running和slave_sql_running都是yes.但是数据并没有同步! 希望有遇到相同问题的朋友,能够告诉我一下解决方案? 首先,如何在同一个服务器安装 ...
- Subway POJ - 2502 最短路
题意:给出地铁线 起点和 终点 坐地铁速度为v2 走路为v1 求起点到终点的最短距离 (答案需要四舍五入这里坑了好久) 拿给出的地铁站点 和起点终点建边即可 然后跑个迪杰斯特拉 #inclu ...
- 对Redis的理解
1.redis使用的场景 热点数据(经常会被查询,但是不经常被修改或者删除的数据)
- Hdoj 1421.搬寝室 题解
Problem Description 搬寝室是很累的,xhd深有体会.时间追述2006年7月9号,那天xhd迫于无奈要从27号楼搬到3号楼,因为10号要封楼了.看着寝室里的n件物品,xhd开始发呆, ...
- 【转】让浏览器格式化显示JSON数据之chrome jsonView插件安装
jsonView 用来让Chrome浏览器能格式化的显示JSON数据. 以上是网上找的方式,且试验成功! 步骤: 1.打开 https://github.com : 2.搜索 jsonView 链接: ...
- [SDOI2015]序列统计(多项式快速幂)
题目描述 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S.小C用这个生成器生成了许多这样的数列.但是小C有一个问 ...
- bzoj4240有趣的家庭菜园(贪心+逆序对)
对家庭菜园有兴趣的JOI君每年在自家的田地中种植一种叫做IOI草的植物.JOI君的田地沿东西方向被划分为N个区域,由西到东标号为1~N.IOI草一共有N株,每个区域种植着一株.在第i个区域种植的IOI ...
- 【mysql】mysql尾部空格
mysql 字段为varchar类型的在查询时候胡忽略尾部空格. 先看表结构 插入一条数据包含空格 在查询是可以查到的 所有在插入数据的时候要对插入字段的数据处理下,php可以用函数trim()去掉两 ...
- 编写高质量代码:改善Java程序的151个建议 --[65~78]
编写高质量代码:改善Java程序的151个建议 --[65~78] 原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱. public class Client65 { public ...
- NLog类库使用探索——编程配置
以编程的方式配置,这是我项目中的,我都不知道为什么使用编程.直接配置不很好吗,估计他也没有研究.直接上步骤和代码: 创建一个LoggingConfiguration对象,用来保存配置信息 至少创建一个 ...