当前位置: 首页 > news >正文

Python 封装 socket 为 [TCP/UDP/MULTICAST] 服务端

在新线程中创建 TCP/UDP/MULTICAST 协议的服务端套接字,接收客户端的连接请求或数据,并调用 on_recv 回调函数处理数据。

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import socket
import threading
import multiprocessingclass ServerSocket:def __init__(self, *, protocol: str, port: int, group: str = '', on_recv: 'function'):"""服务端套接字在新线程中创建 TCP/UDP/MULTICAST 协议的服务端套接字,接收客户端的连接请求或数据,并调用 on_recv 回调函数处理数据。TCP 断开连接的情况:- TCP 正常断开+ 客户端主动断开连接+ 通信期间正常交换数据 (若服务端返回了响应, 则客户端应该接收响应)- TCP 连接已重置+ 客户端主动断开连接+ 服务端返回了响应,但客户端未接收- TCP 连接已终止+ 未通信完毕就已经断开了连接Args:protocol (str): 协议port (int): 端口号group (str, optional): 组播地址. Defaults to ''.on_recv (function, optional): 接收到数据时的回调函数, 参数为 (data: bytes, client_name: str). Defaults to None.Raises:ValueError: 无效的端口号, 应为 [1-65535]ValueError: 无效的协议类型, 应为 [TCP, UDP, MULTICAST]"""if port < 1 or port > 65535:raise ValueError(f'ServerSocket 无效的端口号 "{port}"')if protocol not in ['TCP', 'UDP', 'MULTICAST']:raise ValueError(f'ServerSocket 无效的协议类型 "{protocol}"')if protocol == 'MULTICAST' and not group:raise ValueError(f'ServerSocket 组播协议必须指定组播地址')if protocol != 'MULTICAST' and group:raise ValueError(f'ServerSocket 协议类型 "{protocol}" 请勿设置 group 参数')self.protocol = protocolself.port = portself.group = groupself.on_recv = on_recvself.sock: socket.socket | None = Noneself.tcp_sub_socks: list[socket.socket] = []self.thread: threading.Thread | None = Noneself.__active = Falsedef __str__(self) -> str:if self.protocol == 'MULTICAST':return f'ServerSocket({self.protocol}, {self.group}:{self.port})'return f'ServerSocket({self.protocol}, {self.port})'def __del__(self) -> None:self.close()def __create_socket(self) -> None:match self.protocol:case 'TCP':self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)self.sock.bind(('0.0.0.0', self.port))self.sock.listen(10)case 'UDP':self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)self.sock.bind(('0.0.0.0', self.port))case 'MULTICAST':self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)self.sock.bind(('0.0.0.0', self.port))self.sock.setsockopt(socket.IPPROTO_IP,socket.IP_ADD_MEMBERSHIP,socket.inet_aton(self.group) + socket.INADDR_ANY.to_bytes(4, byteorder='big'))def __send_back(self, client_addr: tuple[str, int], client_sock: socket.socket | None = None) -> 'function':def send_back(data: bytes):if self.protocol == 'TCP':return client_sock.sendto(data, client_addr)return self.sock.sendto(data, client_addr)return send_backdef __tcp_sub_thread(self, client_sock: socket.socket, client_addr: tuple[str, int]) -> None:while self.is_active():try:if not (data := client_sock.recv(1024)):print(f'{self} TCP 子线程 {client_addr} 正常断开')breakself.on_recv and self.on_recv(data=data,client_addr=client_addr,send_back=self.__send_back(client_addr, client_sock),)except ConnectionResetError:print(f'{self} TCP 子线程 {client_addr} 连接已重置')breakexcept ConnectionAbortedError:print(f'{self} TCP 子线程 {client_addr} 连接已终止')breakexcept Exception as e:if self.is_active():print(f'{self} TCP 子线程 {client_addr} 异常: \n{e}')breakif self.is_active(): # 断开或异常self.tcp_sub_socks.remove(client_sock)client_sock.close()def __main_thread(self) -> None:self.__active = Truewhile self.is_active():try:if self.protocol == 'TCP':client_sock, client_addr = self.sock.accept()self.tcp_sub_socks.append(client_sock)threading.Thread(target=self.__tcp_sub_thread, args=(client_sock, client_addr), daemon=True).start()else:data, client_addr = self.sock.recvfrom(1024)self.on_recv and self.on_recv(data=data,client_addr=client_addr,send_back=self.__send_back(client_addr),)except Exception as e:if self.is_active():print(f'{self} 主线程异常 : \n{e}')breakdef start(self, is_process: bool = False) -> bool:"""启动服务端将在新线程中运行,直到调用 close() 关闭,TCP 协议下会创建子线程处理 TCP 连接Args:is_process (bool, optional): 是否以子进程运行. Defaults to False.Returns:bool: 是否启动成功"""try:self.__create_socket()except Exception as e:print(f'{self} 创建失败: \n{e}')return Falseif is_process:self.thread = multiprocessing.Process(target=self.__main_thread, daemon=True)else:self.thread = threading.Thread(target=self.__main_thread, daemon=True)self.thread.start()return Truedef close(self) -> bool:"""关闭服务端Returns:bool: 是否关闭成功"""try:self.__active = Falseif self.protocol == 'TCP':for client_sock in self.tcp_sub_socks:client_sock.shutdown(socket.SHUT_RDWR)client_sock.close()self.tcp_sub_socks.clear()else:self.sock.shutdown(socket.SHUT_RDWR)self.sock.close()if isinstance(self.thread, multiprocessing.Process):self.thread.terminate()else:self.thread.join()except Exception as e:print(f'{self} 关闭失败: \n{e}')return Falsereturn Truedef is_active(self) -> bool:"""返回服务端是否处于活动状态Returns:bool: 是否处于活动状态"""return self.__activequit = False
def on_recv(data, client_addr, send_back):global quitprint(f'收到数据: {data} 来自 {client_addr}')send_back(b'ok')if data == b'q':quit = True# server.close()if __name__ == '__main__':from time import sleepserver = ServerSocket(protocol='TCP', port=60000, on_recv=on_recv)# server = ServerSocket(protocol='UDP', port=60000, on_recv=on_recv)# server = ServerSocket(protocol='MULTICAST', group='224.1.1.1', port=65000, on_recv=on_recv)server.start()while server.is_active():print('等待数据...')if quit:print('退出')server.close()sleep(60)

相关文章:

Python 封装 socket 为 [TCP/UDP/MULTICAST] 服务端

在新线程中创建 TCP/UDP/MULTICAST 协议的服务端套接字&#xff0c;接收客户端的连接请求或数据&#xff0c;并调用 on_recv 回调函数处理数据。 #!/usr/bin/env python # -*- coding: utf-8 -*- import socket import threading import multiprocessingclass ServerSocket:de…...

c++ STL库 unordered_map

#include <iostream #include <string #include <unordered_map int main() { // 创建一个 unordered_map std::unordered_map<std::string, int> wordCount; // 插入元素 wordCount["apple"] 1; wordCount["banana"] 2;// 使用 insert…...

【接口测试】任务1:登录接口

需要技能竞赛软件测试资料的同学们可s聊我&#xff0c;详细了解 任务实现要求 根据系统管理员—登录—接口API文档&#xff0c;编写接口测试用例&#xff0c;分别使用PostMan及JMeter进行接口测试&#xff0c;需要检查系统接口是否能正常工作&#xff0c;返回值是否正确&#…...

二、Spring Boot集成Spring Security之实现原理

Spring Boot集成Spring Security之实现原理 一、Spring Security实现原理概要介绍二、使用WebSecurityConfiguration向Spring容器中注册FilterChainProxy类型的对象springSecurityFilterChain1、未配置securityFilterChain过滤器链时使用默认配置用于生成默认securityFilterCha…...

基于深度学习的点云处理模型PointNet++学习记录

前面我们已经学习了Open3D&#xff0c;并掌握了其相关应用&#xff0c;但我们也发现对于一些点云分割任务&#xff0c;我们采用聚类等方法的效果似乎并不理想&#xff0c;这时&#xff0c;我们可以想到在深度学习领域是否有相关的算法呢&#xff0c;今天&#xff0c;我们便来学…...

Javascript Object.assgin()详解以及深浅拷贝

Object.assign() 方法是 JavaScript 中用于将所有可枚举属性的值从一个或多个源对象复制到目标对象的方法。它将返回目标对象。这是一种浅拷贝&#xff0c;也就是说&#xff0c;如果源对象中的属性是一个对象或数组&#xff0c;那么这个属性的引用将被复制&#xff0c;而不是对…...

Redis篇(应用案例 - UV统计)(持续更新迭代)

目录 一、HyperLogLog 二、测试百万数据的统计 一、HyperLogLog 首先我们搞懂两个概念&#xff1a; UV&#xff1a;全称Unique Visitor&#xff0c;也叫独立访客量&#xff0c;是指通过互联网访问、浏览这个网页的自然人。 1天内同一个用户多次访问该网站&#xff0c;只记录…...

解锁微信小程序新技能:ECharts动态折线图搭配WebSocket,数据刷新快人一步!

在微信小程序中&#xff0c;数据可视化展示越来越受到开发者的重视。本文将为您介绍如何在微信小程序中使用ECharts绘制折线图&#xff0c;并通过WebSocket实现实时更新图表数据。 一、准备工作 创建微信小程序项目 首先&#xff0c;我们需要创建一个微信小程序项目。如果您已…...

上交所服务器崩溃:金融交易背后的技术隐患暴露杭州BGP高防服务器43.228.71.X

一、上交所宕机事件始末 2024 年 9 月 27 日&#xff0c;上交所交易系统突发崩溃&#xff0c;这一事件犹如一颗巨石投入平静的湖面&#xff0c;引起了轩然大波。当天上午&#xff0c;众多投资者反馈券商交易出现延迟问题&#xff0c;随后上交所发布了《关于股票竞价交易出现异常…...

P4、P4D、HelixSwarm 各种技术问题咨询

多年大型项目P4仓库运维经验&#xff0c;为你解决各种部署以及标准工业化流程问题。 Perforce 官网SDPHelixCore GuideHelixSwarm GuideHelixSwarm Download...

Linux 应用层协议HTTP

文章目录 一、初始HTTP协议二、URL格式网络中怎么通过URL进行定位资源呢&#xff1f;编码和解码 三、HTTP的请求格式和响应格式HTTP的请求格式HTTP的响应格式HTTP的请求方法GET方法POST方法GET Vs PostHTTP的封装和分用文件流操作浏览器获得一个完整的网页流程 HTTP的状态码对3…...

Python和C++混淆矩阵地理学医学物理学视觉语言模型和算法模型评估工具

&#x1f3af;要点 优化损失函数评估指标海岸线检测算法评估遥感视觉表征和文本增强乳腺癌预测模型算法液体中闪烁光和切伦科夫光分离多标签分类任务性能评估有向无环图、多路径标记和非强制叶节点预测二元分类评估特征归因可信性评估马修斯相关系数对比其他准确度 Python桑…...

HTTP 协议的基本格式和 fiddler 的用法

HTTP协议格式 HTTP是⼀个⽂本格式的协议.可以通过Chrome开发者⼯具或者Fiddler抓包,分析HTTP请求/响应的细节. 抓包工具的使用 以Fiddler为例. • 左侧窗⼝显⽰了所有的HTTP请求/响应,可以选中某个请求查看详情. • 右侧上⽅显⽰了HTTP请求的报⽂内容.(切换到Raw标签⻚可以看…...

【计算机网络】详解UDP协议格式特点缓冲区

一、UDP 协议端格式 16 位 UDP 长度, 表示整个数据报(UDP 首部UDP 数据)的最大长度&#xff1b;如果16位UDP检验和出错&#xff0c;报文会被直接丢弃。 1.1、检验和出错的几种常见情况 数据传输过程中的比特翻转&#xff1a;在数据传输过程中&#xff0c;由于物理介质或网络设…...

网络安全cybersecurity的几个新领域

一、电力安全 同学们&#xff0c;今天我们来讨论一下为什么网络安全&#xff08;Cybersecurity&#xff09;和电力系统&#xff08;Power Systems&#xff09;这两个看似不同的领域会有交集。其实&#xff0c;这两个领域之间的联系非常紧密。以下我将从多个角度进行解释&#…...

android 原生加载pdf

implementation("androidx.pdf:pdf-viewer-fragment:1.0.0-alpha02") pdf加载链接...

MAE(平均绝对误差)和std(标准差)计算中需要注意的问题

一、MAE&#xff08;平均绝对误差&#xff09; 计算公式&#xff1a; yi​ 是第i个实际值y^​i​ 是第i个预测值 计算方法&#xff1a; MAE就是求实际值与预测值之间的误差&#xff0c;需要给出预测值和原始的实际值 二、std&#xff08;标准差&#xff09; 计算公式&#x…...

03实战篇:把握667分析题的阅读材料、题目

本节你将学习到&#xff1a; 如何快速识别阅读材料的有效信息如何把握题目的作答方向 在正式进入具体的实战之前&#xff0c;我想先来讲一讲如何利用给定阅读材料、如何分析题目来确保不偏题等基础性知识。 高效利用给定阅读材料的方法 根据博主的实战经验来看&#xff0c;阅…...

C++系列-多态

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 多态 多态就是不同类型的对象&#xff0c;去做同一个行为&#xff0c;但是产生的结果是不同的。 比如说&#xff1a; 都是动物叫声&#xff0c;猫是喵喵&#xff0c;狗是汪汪&am…...

基于C++和Python的进程线程CPU使用率监控工具

文章目录 0. 概述1. 数据可视化示例2. 设计思路2.1 系统架构2.2 设计优势 3. 流程图3.1 C录制程序3.2 Python解析脚本 4. 数据结构说明4.1 CpuUsageData 结构体 5. C录制代码解析5.1 主要模块5.2 关键函数5.2.1 CpuUsageMonitor::Run()5.2.2 CpuUsageMonitor::ComputeCpuUsage(…...

fish-speech语音大模型本地部署

文章目录 fish-speech模型下载编译部署 小结 fish-speech模型 先说下fish-speech模型吧&#xff0c;可以先看下官网。如下&#xff1a; 这就是一个模型&#xff0c;可以根据一个样例声音&#xff0c;构建出自己需要的声音。其实&#xff0c;这个还是有很多用途的&#xff1b;…...

如何写出更牛的验证激励

前言 芯片验证是为了发现芯片中的错误而执行的过程&#xff0c;它是一个破坏性的过程。完备的验证激励可以更有效地发现芯片错误&#xff0c;进而缩短验证周期。合格的验证激励必须能产生所有可能的验证场景(完备性)&#xff0c;包括合法和非法的场景&#xff0c;并保持最大的…...

EasyCVR视频汇聚平台:解锁视频监控核心功能,打造高效安全监管体系

随着科技的飞速发展&#xff0c;视频监控技术已成为现代社会安全、企业管理、智慧城市构建等领域不可或缺的一部分。EasyCVR视频汇聚平台作为一款高性能的视频综合管理平台&#xff0c;凭借其强大的视频处理、汇聚与融合能力&#xff0c;在构建智慧安防/视频监控系统中展现出了…...

面对大文件(300G以上)如何加速上传速度

解题思路 采用分片上传&#xff0c;同时每个分片多线程上传可以加速上传速度&#xff0c;上传速度提升10倍左右 在阿里云OSS Go SDK中&#xff0c;bucket.UploadStream 函数并没有直接提供&#xff0c;而是通过 bucket.UploadFile 或者 bucket.PutObject 等函数来实现文件上传…...

基于 Redis 实现消息队列的深入解析

目录 Redis 消息队列简介Redis 消息队列的实现方式 2.1 使用 List 实现简单队列2.2 使用 Pub/Sub 模式实现消息发布与订阅2.3 使用 Stream 实现高级队列 Redis 消息队列的特点与优势Redis 消息队列的应用场景Redis 消息队列的局限性及应对方案总结 Redis 消息队列简介 Redis…...

C++(string类的实现)

1. 迭代器、返回capacity、返回size、判空、c_str、重载[]和clear的实现 string类的迭代器的功能就类似于一个指针&#xff0c;所以我们可以直接使用一个指针来实现迭代器&#xff0c;但如下图可见迭代器有两个&#xff0c;一个是指向的内容可以被修改&#xff0c;另一个则是指…...

nrf 24l01使用方法

1、frequency 频率基础频率2.400G HZ RF_CH RF_CH10 CH2.4G0.01G2.41G 2、逻辑通道6个 pipe 时间片不同&#xff0c;占用同一个频率 发送时&#xff0c;只有一个pipe 接受时可以有6个pipe 3、通讯速率 air data rate rf_dr 寄存器设置 有两种速率 2M 1M RF_DR0 1M ,…...

C语言普及难度三题

先热个身&#xff0c;一个长度为10的整型数组&#xff0c;输出元素的差的max和min。 #include<stdio.h> int main() {int m[10],i0,max,min;for(i0;i<10;i){scanf("%d",&m[i]);}minm[0];maxm[0];for (i 0; i <10; i){if(min>m[i]) min m[i];i…...

10.4每日作业

C1 C2 C1 C2...

日常工作记录:服务器被攻击导致chattr: command not found

在深夜的寂静中&#xff0c;公司的服务器突然遭遇了一场突如其来的攻击。特别是nginx配置文件无法修改&#xff0c;仿佛预示着不祥的预兆&#xff0c;面对这突如其来的灾难&#xff0c;技术人员迅速响应。 这时候需要chattr&#xff0c;但是执行的chattr -i xxx的时候&#xf…...