python socket编程
概念说明
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_le