Python基于Socket实现TCP长连接框架详解

Finn
Finn
发布时间:2026-10-15| 4人浏览过
原创

本文介绍如何使用Python的Socket库构建TCP长连接框架,适用于游戏及IM类应用。通过封装初始化参数、建立连接、数据收发线程及异常重连机制,实现稳定的长连接通信。示例代码展示了基于select的循环处理、十六进制数据封装及断线自动重连逻辑,为开发者提供参考实现。

Python基于Socket实现TCP长连接框架详解

本文旨在展示如何使用Python实现协议中常见的TCP长连接框架。

深入分析各类协议后可发现,许多应用场景,尤其是游戏类和即时通讯(IM)类应用,通常采用长连接方式以维持客户端与服务器之间的持续交互,且这些长连接多基于TCP协议承载。

在模拟客户端行为时,根据具体应用服务器的实现差异,部分场景下的长连接并非强制要求,但在某些情况下,必须实现长连接功能。例如,近期分析的某应用虽主要依赖HTTP协议进行交互,但其通过TCP长连接传输了关键信息;若未实现长连接,将导致大量信息无法被正确处理。

在Python中实现HTTP协议相对简便,同样,利用内置的socket库也能轻松实现TCP协议。需要注意的是,TCP长连接中传输的数据通常为十六进制格式,且协议往往非标准,因此需根据具体的协议分析结果自行封装数据格式。

以下以涉及TCP长连接的协议为例,提供一个TCP长连接框架的参考实现。该代码片段源自实际样例,并非完整项目,供有需求的开发者参考。

框架初始化与核心函数设计

该TCP长连接框架首先进行外部包装,初始化关键参数,包括长连接所需的IP地址、端口号以及socket套接字对象等。

self.longip='im.langren001.com'
        self.longport= 6656
        self.threadLock = threading.Lock()
        self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
        self.longlinktcpstart2()
        tlonglink = threading.Thread(target=lrsuser.longlinktcpth2,name='mainlink_'+ self.playinfo['uid'], args=(self,))
        tlonglink.start()
        self.threadinfo.append(tlonglink)

此初始化过程调用了两个核心函数:一是longlinktcpstart2函数,负责建立socket连接并处理连接建立初期的交互逻辑;二是longlinktcpth2函数,作为一个独立线程,专门负责连接内的数据收发处理。尽管这两个功能可以合并实现,但为了更便捷地处理socket异常断开情况,将其拆分为两个函数。

连接建立与数据交互实现

longlinktcpstart2函数的具体实现如下:

def longlinktcpstart2(self):
        server_address = (self.longip, int(self.longport))
        self.savelogs('longlinktcpstart2', 'Connecting to %s:%d.' % server_address)
        self.sockmain.connect(server_address)
        self.databuf = b''
        message = genbaseinfo.genalive()
        self.sockmain.sendall(message)
        message = genbaseinfo.genfirstdata()
        if len(message)==0:
            self.savelogs('longlinktcpstart2', 'genfirstdata error ')
            return False
        self.sockmain.sendall(message)
        self.longlinkcnt=2
        cnt = 0
        while (cnt < 2):
            try:
                buf = self.sockmain.recv(2048)
                sz = len(buf)
                self.savelogs('longlinktcpstart2', "recv data len "+str(sz) )
                if sz > 0:
                    self.databuf +=buf
                    self.dealdatabuf()
                    if cnt == 0:
                        alivemsg =  genbaseinfo.genalive()
                        self.sockmain.sendall(alivemsg)
                        self.savelogs('longlinktcpstart2', "sendalive")
                        regtime=int(round(time.time() * 1000))-random.randint(14400000,25200000)
                        regtime=regtime*1000
                        pcode = self.versionstr + '.0'
                        message =  genbaseinfo.genseconddata()
                        if len(message) == 0:
                            self.savelogs('longlinktcpstart2', 'genseconddata error ')
                            return False
                        self.sockmain.sendall(message)
                        self.longlinkcnt = self.longlinkcnt + 1
                    elif cnt == 1:
                        pcode = self.versionstr + '.0'
                        message =  genbaseinfo.genotherdata()
                        if len(message) == 0:
                            self.savelogs('longlinktcpstart2', 'genthirddata error ')
                            return False
                        self.sockmain.sendall(message)
                        self.longlinkcnt = self.longlinkcnt + 1
                    cnt = cnt + 1
                else:
                    self.savelogs('longlinktcpstart2', 'recv data alive')
            except:  # socket.error
                self.savelogs('longlinktcpstart2', 'socket error,do connect fail')
                return False
 
 
        return True

代码中的genbaseinfo相关函数可忽略,其作用是生成发送的消息数据,开发者可根据实际需求替换为自定义函数。dealdatabuf函数用于处理接收到的消息数据,这两个函数的具体实现均需依据具体的协议分析结果而定。需注意,发送的数据和接收后需处理的数据均应按十六进制格式进行处理,此处不再赘述。

数据收发线程与异常处理机制

线程longlinktcpth2采用循环机制,只要协议未退出,循环便不会结束,其具体实现如下:

def longlinktcpth2(self):
        tmalive = 0;
        r_inputs = set()
        r_inputs.add(self.sockmain)
        w_inputs = set()
        w_inputs.add(self.sockmain)
        e_inputs = set()
        e_inputs.add(self.sockmain)
        tm=int(round(time.time()))
        self.savelogs('longlinktcpth2', 'enter' )
        while (self.quitflag==0):
            try:
                r_list, w_list, e_list = select.select(r_inputs, w_inputs, e_inputs, 1)
                for event in r_list:
                    try:
                        buf = event.recv(2048)
                        sz = len(buf)
                        self.savelogs('longlinktcpth2', "loop recv data len:"+ str(sz) )
                        if sz > 0:
                            self.databuf += buf
                            self.dealdatabuf()
                            alivemsg = genbaseinfo.genalive()
                            self.sockmain.sendall(alivemsg)
                            self.savelogs('longlinktcpth2', "sendalive")
                        else:
                            self.savelogs('longlinktcpth2', "远程断开连接,do reconnect")
                            r_inputs.clear()
                            time.sleep(3)
                            self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                            self.longlinktcpstart2()
                            r_inputs = set()
                            r_inputs.add(self.sockmain)
                            w_inputs = set()
                            w_inputs.add(self.sockmain)
                            e_inputs = set()
                            e_inputs.add(self.sockmain)
                    except Exception as e:
                        self.savelogs('longlinktcpth2', str(e))
                self.threadLock.acquire()
                if (len(self.msglist) > 0):
                    msg = self.msglist.pop(0)
                    self.threadLock.release()
                    self.sockmain.sendall(msg)
                    self.savelogs('longlinktcpth2',"send a msg")
                else:
                    self.threadLock.release()
                tmnow=int(round(time.time()))
                if tmnow-tm>30:
 
 
                    message = genbaseinfo.genotherdata()
                    if len(message) == 0:
                        self.savelogs('longlinktcpth2', 'genalivedata error ')
                        return False
                    self.sockmain.sendall(message)
                    self.savelogs('longlinktcpth2', "send alivemsg"+str(self.longlinkcnt))
                    self.longlinkcnt = self.longlinkcnt + 1 #这个要一条连接统一,不能乱,回头加锁
                    tm=tmnow
                if len(w_list) > 0:  # 产生了可写的事件,即连接完成
                    self.savelogs('longlinktcpth2',str(w_list))
                    w_inputs.clear()  # 当连接完成之后,清除掉完成连接的socket
 
 
                if len(e_list) > 0:  # 产生了错误的事件,即连接错误
                    self.savelogs('longlinktcpth2', str(e_list))
                    e_inputs.clear()  # 当连接有错误发生时,清除掉发生错误的socket
            except OSError as e:
                self.savelogs('longlinktcpth2', 'socket error,do reconnect')
                time.sleep(3)
                self.sockmain = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.longlinktcpstart2()
                r_inputs = set()
                r_inputs.add(self.sockmain)
                w_inputs = set()
                w_inputs.add(self.sockmain)
                e_inputs = set()
                e_inputs.add(self.sockmain)
                
        self.savelogs('longlinktcpth2', 'leave')

鉴于该代码主要在Windows环境下运行,因此longlinktcpth2线程采用了select机制而非epoll。在循环中加入了异常处理逻辑:若发生异常导致连接断开,则调用longlinktcpstart2函数重新建立连接,而不会退出循环;其余逻辑与longlinktcpstart2内部一致。

由于TCP连接本质上是流式概念,因此需要对数据进行缓存和拼接,这正是上述代码中databuf变量的作用。它旨在防止每次接收到的数据不完整或数据量过大,从而便于后续处理。这也是合格开发者在编码过程中应具备的基本素养和自我提升方向。

至此,关于使用Python通过Socket实现协议TCP长连接框架的介绍已完成。如需了解更多Python TCP长连接相关内容,欢迎搜索本站过往文章或继续浏览后续相关文章,感谢大家的支持!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。