socketserver 模块实现并发及文件下载程序

2024-01-21 02:18

本文主要是介绍socketserver 模块实现并发及文件下载程序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

上章回顾

在讲解 socketserver 模块之前先补充一下上一章节的一个示例:

ceeb653ejw1f90p0idtk0g2046046t9m

实现客户端从服务端下载文件的功能,能hash校验(Windows和Linux测试成功,代码比较low仅供观望)

  • 服務端
# coding=utf-8
from socket import *
import json
import struct
import os,hashlibserver = socket(AF_INET,SOCK_STREAM)
# server.bind(("192.168.12.222",8090))
server.bind(("127.0.0.1",8090))
server.listen(5)while 1:print("connection...")conn,addr = server.accept()print(f"from {addr} conn")while 1:try:file_path = conn.recv(1024)file_path = os.path.normpath(file_path.decode("utf-8"))if not os.path.isfile(file_path):conn.send("4044".encode("utf-8"))else:file_size = os.path.getsize(file_path)file_name = os.path.basename(file_path)m = hashlib.md5()m.update(str(file_size).encode("utf-8"))md5 = m.hexdigest()header_dic = {"file_name":file_name,"file_size":file_size,"hash":md5}header_json = json.dumps(header_dic)header_bytes = header_json.encode("utf-8")header_bytes_len = struct.pack("i",len(header_bytes))conn.send(header_bytes_len)conn.send(header_bytes)with open(file_path,"rb")as f:for line in f:conn.send(line)except Exception:break
  • 客户端
# coding=utf-8
from socket import *
import json
import struct
import os
import hashlib# 打印进度条
def progress(percent, symbol='█', width=40):if percent > 1:  # 超过 100% 的时候让其停在 1percent = 1  # 可以避免进度条溢出show_progress = ("▌%%-%ds▌" % width) % (int(percent * width) * symbol)print("\r%s %.2f%%" % (show_progress, percent * 100), end='')client = socket(AF_INET,SOCK_STREAM)
# client.connect(("192.168.12.222",8090))
client.connect(("127.0.0.1",8090))while True:file_path = input("Please enter the file path(q/exit)>>").strip()if file_path.lower() == "q":breakif len(file_path) == 0:continueto_path = input("Please enter the save directory(q/back)>>").strip()if to_path.lower() == "q":continueif not os.path.isdir(to_path):print("not find");continueelse:file_name = input("Please enter filename(q/back)>>").strip()if file_name.lower() == "q":continuegoal_path = os.path.join(to_path,file_name)client.send(file_path.encode("utf-8"))bytes_4 = client.recv(4)if bytes_4.decode("utf-8") == "4044":print("not find");continueelse:header_bytes_len = struct.unpack("i",bytes_4)[0]header_bytes = client.recv(header_bytes_len)header_dic = json.loads(header_bytes.decode("utf-8"))date_len = header_dic["file_size"]hash_md5 = header_dic["hash"]recv_len = 0with open(goal_path,"wb")as f:while 1:date = client.recv(1024)recv_len += len(date)percent = recv_len / date_len  # 接收的比例progress(percent, width=40)    # 进度条的宽度40f.write(date)if recv_len == date_len: breakm = hashlib.md5()m.update(str(os.path.getsize(goal_path)).encode("utf-8"))if hash_md5 == m.hexdigest():          # hash 值校验print("\nHash auth succeed\nFile saved...")else:os.remove(goal_path)               # 校验失败内容删除print("Hash auth failed!!")
  • Windows 下测试

image-20210118212633746

  • Linux 下测试

image-20210118211514263

  • 两次的文件

image-20210118212703003

使用 socketserver 模块实现并发

1.socketserver 模块简单介绍

基于 TCP 的套接字, 关键就是两个循环, 一个是连接循环, 另一个是通信循环, 分成两件事去做

socketserver 模块中有两大类, 一个是 server 类, 专门干连接的事, 一个是 request 类, 专门干通信的事

目前只是简单使用 socketserver 模块来实现并发效果, 后面章节再深入研究

2.基于 TCP 的 socketserver 自定义类中的属性和方法介绍

  • handle( ) : 用于连接循环
  • self.server : 套接字对象
  • self.request : 建成的连接, 相当于前面用的 ‘conn’
  • self.client_address : 客户端地址和端口号, 是个元组
  • self.serve_forever( ) : 永久提供服务, 一个死循环, 对应的是连接循环
  • socketserver.ThreadingTCPServer(bind_and_activate=True) : 第一个参数为服务端绑定的ip和端口, 第二的为指定的类, 第三个可以不写,默认为True,设置监听

3.基于 UDP 的 socketserver 自定义类中属性和方法介绍

  • handle( ) : 用于连接循环
  • self.request : 是一个元组, 第一个元素是客户端发来的数据, 第二部分是服务端的udp套接字对象
  • self.client_address : 客户端ip和端口
  • self.serve_forever( ) : 永久提供服务, 一个死循环, 对应的是连接循环
  • socketserver.ThreadingUDPServer((“127.0.0.1”,8089),MyRequestHandler) : 第一个参数为服务端绑定的ip和端口, 第二的为指定的类

4.基于 TCP 实现并发

  • 服务端
import socketserverclass MyRequestHandler(socketserver.BaseRequestHandler):  # 必须继承这个类来使用它的功能def handle(self):  # 用于通信循环while True:try:data = self.request.recv(1024)if len(data) == 0:breakself.request.send(data.upper())except ConnectionResetError:breakself.request.close()# 做绑定 ip和端口并设置监听的事, "bind_and_activate" 默认等于 "True"
s = socketserver.ThreadingTCPServer(("127.0.0.1",8089),MyRequestHandler,bind_and_activate=True)
s.serve_forever()  # 用于建立连接, 之后交给 handle 进行通信循环
  • 客户端测试例( 可以开启多台)
from socket import *client = socket(AF_INET,SOCK_STREAM)
client.connect(("127.0.0.1",8089))while True:msg = input(">>").strip()if len(msg) == 0:continueclient.send(msg.encode("utf-8"))data = client.recv(1024)print(data.decode("utf-8"))client.close()

5.基于 UDP 实现并发

  • 服务端
import socketserverclass MyRequestHandle(socketserver.BaseRequestHandler):def handle(self):while True:date,conn = self.requestprint(f"来自[{self.client_address}]的信息 : {date.decode('utf-8')}")conn.sendto(date.upper(),self.client_address)s = socketserver.ThreadingUDPServer(("127.0.0.1",8080),MyRequestHandle)
s.serve_forever()
  • 客户端(可开启多台)
from socket import *client = socket(AF_INET,SOCK_DGRAM)while True:date = input(">>").strip()client.sendto(date.encode("utf-8"),("127.0.0.1",8080))res,addr = client.recvfrom(1024)print(f"来自服务端的消息 : {res.decode('utf-8')}")

这篇关于socketserver 模块实现并发及文件下载程序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/628076

相关文章

Python的Darts库实现时间序列预测

《Python的Darts库实现时间序列预测》Darts一个集统计、机器学习与深度学习模型于一体的Python时间序列预测库,本文主要介绍了Python的Darts库实现时间序列预测,感兴趣的可以了解... 目录目录一、什么是 Darts?二、安装与基本配置安装 Darts导入基础模块三、时间序列数据结构与

Python使用FastAPI实现大文件分片上传与断点续传功能

《Python使用FastAPI实现大文件分片上传与断点续传功能》大文件直传常遇到超时、网络抖动失败、失败后只能重传的问题,分片上传+断点续传可以把大文件拆成若干小块逐个上传,并在中断后从已完成分片继... 目录一、接口设计二、服务端实现(FastAPI)2.1 运行环境2.2 目录结构建议2.3 serv

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Nginx部署HTTP/3的实现步骤

《Nginx部署HTTP/3的实现步骤》本文介绍了在Nginx中部署HTTP/3的详细步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录前提条件第一步:安装必要的依赖库第二步:获取并构建 BoringSSL第三步:获取 Nginx

MyBatis Plus实现时间字段自动填充的完整方案

《MyBatisPlus实现时间字段自动填充的完整方案》在日常开发中,我们经常需要记录数据的创建时间和更新时间,传统的做法是在每次插入或更新操作时手动设置这些时间字段,这种方式不仅繁琐,还容易遗漏,... 目录前言解决目标技术栈实现步骤1. 实体类注解配置2. 创建元数据处理器3. 服务层代码优化填充机制详

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja