33.python socket

news2024/12/25 2:21:44

python socket编程

  • 概念说明
  • 心跳包的作用
  • 基于以上知识的基础上我们来实现一个代码
    • socket server
    • socket client
    • 执行结果

概念说明

socket传输数据是基于字节流的,默认情况下是无边界的字节流。 一般情况下数据里中包含心跳包和数据包。数据包就是我们实际需要发送给server端的数据。

心跳包的作用

有人可能会有疑问,tcp协不是长连接么,只要建立了连接在不出意外的情况下不是可以一直维持连接吗?为什么还需要心跳包。
在TCP/IP网络通信中,尽管TCP连接本身是面向连接的、可靠的传输层协议,并且TCP协议自身包含了许多机制来确保数据的可靠传输(如序列号、确认应答、超时重传等),但这并不意味着TCP连接就是“永远在线”或“长连接”就一定不会出现问题。实际上,长连接(也称为持久连接)指的是TCP连接在数据传输完成后不会被立即关闭,而是保持一段时间以便后续的数据传输,这样可以减少因为频繁建立和关闭连接所带来的开销。

然而,即使使用了长连接,也仍然可能遇到以下问题:

  • 网络问题:网络中的设备(如路由器、交换机、防火墙等)可能会因为各种原因(如负载均衡、故障恢复、安全策略等)而中断或重置空闲的TCP连接。这些设备通常会有超时时间设置,用于清理长时间没有数据交换的连接。
  • NAT(网络地址转换)超时:在使用NAT的私有网络中,NAT设备可能会因为超时而丢弃空闲的TCP连接。这是因为NAT表项资源有限,需要回收长时间未使用的表项以释放资源。
  • 应用程序故障:应用程序本身也可能因为异常、崩溃或重启等原因而失去对TCP连接的跟踪,导致连接处于“挂起”状态。
  • 负载均衡器或代理服务器:在客户端和服务器之间部署负载均衡器或代理服务器时,这些中间设备也可能因为超时或负载均衡策略而关闭空闲连接。
    为了解决这些问题,心跳包(Heartbeat Packet)被引入。心跳包是一种定期发送的小数据包,用于在客户端和服务器之间保持连接的活跃状态,并通知对方自己仍然在线且愿意继续通信。通过发送心跳包,可以:

检测死连接:如果一方长时间没有收到对方的心跳包,则可以认为对方已经不可用,从而关闭连接并释放资源。
绕过NAT超时:定期的心跳包可以确保NAT表项不被超时删除,从而保持连接的活性。
保持负载均衡器或代理服务器的连接状态:类似地,心跳包也可以帮助维持负载均衡器或代理服务器中的连接状态,防止它们因为超时而关闭连接。
因此,尽管TCP连接本身是面向连接的,但在长连接场景中,心跳包仍然是保持连接活跃性和可靠性的重要手段之一。

基于以上知识的基础上我们来实现一个代码

socket server

import socket
import struct
import json
import time
import threading

"""
    socket_server.py
    ~~~~~~~~~~~~~~~~

    socket server

"""

import logging
logger = logging.getLogger("[SOCKET]")
logger.handlers.clear()
logger.setLevel(logging.DEBUG)
streamHandler = logging.StreamHandler()
streamHandler.setLevel(logging.DEBUG)
streamHandler.setFormatter(logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s"))
logger.addHandler(streamHandler)
lock = threading.RLock

class SocketServer(object):
    def __init__(self, host='127.0.0.1', port=9090):
        self.host = host
        self.port = port
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    def _t(self):
        while True:
            time.sleep(0.01)
            # 读取4字节头长
            header_length = self._read_4()
            # 读取头
            header = json.loads(self._read_header(header_length).decode("utf-8"))
            msg_type = header["msg_type"]
            if msg_type == "heart":
                logger.info("header=%s,是心跳包" % header)
            elif msg_type == "data":
                body_length = header["body_length"]
                body = json.loads(self._read_body(body_length).decode("utf-8"))
                logger.info(f"header=%s, 数据包 data=%s" %(header, body))
            else:
                logger.error(f"Received Unknown msg_type from {addr}")
    def start(self):
        self.server_socket.bind((self.host, self.port))
        self.server_socket.listen()
        # 接受客户端连接
        self.client_socket, addr = self.server_socket.accept()
        print(f"Connected by {addr}")
        thread = threading.Thread(target=self._t)
        thread.start()

    def _read_4(self):
        data = b''
        while True:
            data += self.client_socket.recv(4 - len(data))
            if len(data) == 4:
                break
        header_length = struct.unpack('>I', data)[0]  # 将 4 字节数据解析为整数
        return header_length

    def _read_header(self, header_length):
        data = b''
        while len(data) < header_length:  # 确保读取完整的 header_length 字节
            data_chunk = self.client_socket.recv(header_length - len(data))
            data += data_chunk
        return data

    def _read_body(self, body_length):
        data = b''
        while len(data) < body_length:  # 确保读取完整的 body_length 字节
            data_chunk = self.client_socket.recv(body_length - len(data))
            data += data_chunk
        return data
# 启动server
if __name__ == "__main__":
    server = SocketServer()
    server.start()

socket client

import socket
import struct
import json
import time
import threading
class SocketClient(object):
    def __init__(self, host='127.0.0.1', port=9090):
        self.host = host
        self.port = port
        self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.lock=threading.RLock()

    def connect(self):
        self.client_socket.connect((self.host, self.port))

    def _send_heartbeat(self):
        while True:
            self.lock.acquire()
            header_dict = {
                "msg_type": "heart",
                "body_length": 0  # 因为心跳包没有body
            }
            header = json.dumps(header_dict)
            header_length = struct.pack('>I', len(header))  # 打包header长度为4字节的整数

            self.client_socket.send(header_length)
            self.client_socket.send(header.encode('utf-8'))
            logger.info("发送头。。。。。。")
            self.lock.release()
            time.sleep(5)

    def send_data(self, data):
        while True:
            self.lock.acquire()
            body = json.dumps(data)

            header_dict = {
                "msg_type": "data",
                "body_length": len(body)
            }
            header = json.dumps(header_dict)
            header_length_packed = struct.pack('>I', len(header))  # 打包header长度的长度为4字节的整数
            # 先发送4字节长度的header长度
            self.client_socket.send(header_length_packed)
            # 再发送header
            self.client_socket.send(header.encode('utf-8'))
            # 最后发送body
            self.client_socket.send(body.encode('utf-8'))
            logger.info("发送数据。。。。。。成功")
            self.lock.release()
            time.sleep(3)

    def close(self):
        self.client_socket.close()
# 启动客户端
if __name__ == "__main__":
    client = SocketClient()
    client.connect()
    # 发送心跳包
    t_heart = threading.Thread(target=client._send_heartbeat)
    t_heart.start()
    # 发送数据包
    t_data = threading.Thread(target=client.send_data, args=({"key": "value", "number": 123},))
    t_data.start()

    t_heart.join()
    t_data.join()

执行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2078715.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中国建筑轮廓数据

建筑轮廓数据是建筑的边界矢量数据&#xff0c;一般该数据属性中会记录对应建筑的高度或者楼层数&#xff0c;通过建筑轮廓数据置顶的高程字段拉伸&#xff0c;就可以得到建筑白盒模型&#xff0c;所以&#xff0c;我们在各类导航地图中看到的白盒模型&#xff0c;实际上是建筑…

深度剖析:医疗行业财务报表的核心要素与解析策略

在当今医疗行业中&#xff0c;财务报表分析扮演着至关重要的角色。医疗机构需要通过对财务数据的准确分析来做出关键决策&#xff0c;管理资源&#xff0c;改善效率&#xff0c;并确保最终提供高质量的医疗服务。本文将深入探讨医疗行业中财务报表分析的重要性、关键指标和分析…

《一种个性化逻辑定制与类置换方案》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

通过违法app发现大量网站被挂黑页

免责声明&#xff1a;文章来源于真实事件&#xff0c;关键信息已经打码处理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一…

AI搜索的商业模式困境:Perplexity从拒绝广告到高价广告的转变

随着人工智能技术的发展&#xff0c;AI搜索逐渐成为人们日常生活中不可或缺的一部分。在这个领域&#xff0c;Perplexity曾被认为是AI搜索领域的领军企业&#xff0c;以其强大的智能搜索能力脱颖而出。然而&#xff0c;随着OpenAI的SearchGPT发布在即&#xff0c;Perplexity似乎…

掌握结构型模式——全景回顾

在前几篇文章中&#xff0c;我们详细探讨了多种结构型设计模式&#xff0c;今天来进行一个大总结——结构型设计模式主要关注类与对象的组合和组织&#xff0c;确保我们能够构建出稳固、灵活且易于维护的软件系统。无论你是初学者还是有经验的开发者&#xff0c;这篇文章都会帮…

计算循环冗余码(CRC)--软考笔记

1、什么是CRC循环冗余码&#xff08;CRC&#xff09; CRC&#xff08;Cyclic Redundancy Check&#xff09;是一种用于检测数据传输错误的校验码。它通过一个预定义的生成多项式来计算一个固定长度的校验值&#xff0c;这个值被附加到原始数据上一起发送。接收端使用相同的生成…

二叉树 - 完全二叉树的节点个数

222. 完全二叉树的节点个数 方法一&#xff1a;递归 /*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val (valundefined ? 0 : val)* this.left (leftundefined ? null : left)* this.right (rightundefined ? nul…

多商户2.3.0后台顶部添加修改密码修复方法

问题&#xff1a;后台登录不能修改自己的密码&#xff1b; 解决方法&#xff1a; 修改前端代码&#xff0c;文件路径&#xff08;平台后台&#xff0c;商户后台一样的修改方法&#xff09;&#xff1a;src/layout/navBars/breadcrumb/user.vue 修改第一处 代码&#xff1a; 修…

IM即时通讯给娱乐社交、游戏等行业带来了什么影响?看这篇就知道

企业IM即时通讯技术的发展和应用&#xff0c;对我们的生活、工作、沟通和交流带来了显著的影响和改变。 IM即时通讯技术的发展不仅改变了我们的沟通方式&#xff0c;还提高了工作效率&#xff0c;促进了团队协作&#xff0c;保障了信息安全&#xff0c;并推动了业务创新。随着技…

机器人学导论之连杆参数

目录 一、连杆参数[1] 二、将下肢看作二连杆结构 三、参考文献 一、连杆参数[1] 1.1关节角 绕轴&#xff0c;从旋转到的角度。 备注&#xff1a;从z轴正方向看&#xff0c;顺时针为正&#xff0c;逆时针为负。 图 1 平面三连杆操作臂 以图1为例子&#xff0c; 表示…

文献解读-农业-第二十九期|《β-淀粉酶和磷脂酸参与板栗种子萌发》

关键词&#xff1a;农业&#xff1b;基因测序&#xff1b;变异检测&#xff1b; 文献简介 标题&#xff08;英文&#xff09;&#xff1a;Beta-amylase and phosphatidic acid involved in recalcitrant seed germination of Chinese chestnut标题&#xff08;中文&#xff09…

岩土工程中的渗流问题:有限单元法的理论与实践

有限单元法在岩土工程问题中应用非常广泛&#xff0c;很多商业软件如Plaxis/Abaqus/Comsol等都采用有限单元解法。尽管各类商业软件使用方便&#xff0c;但其使用对用户来说往往是一个“黑箱子”。相比而言&#xff0c;开源的有限元程序计算方法透明、计算过程可控&#xff0c;…

宝藏!盟主自控独家讲义:《掌中宝》(精卫篇)1-9章:甄选部分

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;盟主自控独家讲义&#xff1a;《掌中宝》(精卫篇)。 Part1&#xff1a;资料封面&目录 Part2&#xff1a;资料各个章节具体内容 自控专属数学基础储备 第1章 自动控制的基本概念 第2章 控制系统的数学模型 第3章…

8.26算法训练

1.八皇后 Checker Challenge 输入&#xff1a; 6输出&#xff1a; 2 4 6 1 3 5 3 6 2 5 1 4 4 1 5 2 6 3 4是以前寒假写过的题目&#xff0c;所以有的影响&#xff0c;大致思路就是用深度遍历然后判断是否在对角线上就ok了&#xff0c;有大概思路的话&#xff0c; 还是不难的…

比特币的签名和验证(基于ECDSA)

比特币&#xff08;Bitcoin&#xff09;和以太坊&#xff08;Ethereum&#xff09;等区块链技术使用了加密算法来确保交易的安全性。私钥签名和公钥验证是这些算法的核心部分&#xff0c;主要用于证明交易的发起者拥有交易中使用的资金的控制权&#xff0c;而不需要暴露私钥本身…

【开源分享】java+swing+mysql简单学生信息管理系统设计与实现

个人主页&#xff1a;程序员杨工 个人简介&#xff1a;从事软件开发多年&#xff0c;前后端均有涉猎&#xff0c;具有丰富的开发经验 博客内容&#xff1a;全栈开发&#xff0c;分享Java、Python、Php、小程序、前后端、数据库经验和实战 文末有本人名片&#xff0c;希望和大家…

大模型学习全面教程:零基础入门至精通,一篇文章全掌握

人人都看得懂的大模型简介 大模型就像一座庞大的图书馆&#xff0c;里面有非常多的书籍。但与普通图书馆不同的是&#xff0c;这座图书馆中的每本书都是关于不同事物的描述和知识。而这些书籍中的每一页都代表了这个事物的一些特征或细节。现在&#xff0c;想象一下&#xff0…

蓝牙耳机哪个品牌最具有性价比?四大性价比拉满产品推荐!

蓝牙耳机哪个品牌最具有性价比&#xff1f;目前市面上的蓝牙耳机层出不重&#xff0c;蓝牙耳机的的品类也五花八门的&#xff0c;想要选择一款满意的蓝牙耳机也是需要花费一定的时间&#xff0c;大家购买时一定要格外注意&#xff0c;劣质耳机产品不仅使耳朵受到伤害&#xff0…

Python与Plotly实现多维度数据的动态可视化——交互式股票价格

目录 准备工作安装必要的库导入库 获取数据数据预处理创建交互式图表方法一&#xff1a;基本多线图方法二&#xff1a;带有滚动和区间选择的交互式图表方法三&#xff1a;可视化股票每日回报率的箱线图方法四&#xff1a;添加注释和标记的交互式图表 完整代码 在金融数据分析中…