Python版本Zinx——(10)链接启动/停止自定义钩子函数

2023-08-29  本文已影响0人  爱折腾的胖子

  最近想研究一下关于长链接的相关内容,在B站上看到了Zinx框架的视频,是Golang语言的框架,本着更好的理解框架的内容,按照整个Zinx课程的进度,制作一个Python版本的Zinx框架。有关于Zinx框架的具体内容,可以看框架作者的介绍
  python版本的Zinx,基于Gevent 22.10.2,使用协程功能。

  golang版本的Zinx项目,项目中两个文件夹,ziface和znet。

  • ziface主要是存放一些Zinx框架的全部模块的抽象层接口类。
  • znet模块是zinx框架中网络相关功能的实现,所有网络相关模块都会定义在znet模块中。
    └── zinx
     ├── ziface
     │  └──
     └── znet
        ├──

  python中的关键字没有interface,但是可以使用抽象基类(abstract base class)和第三方库来实现类似于接口的功能。在实际开发中,我们可以根据具体需求选择合适的实现方式。
  暂时使用抽象基类的形式模拟接口的实现。


  本节开发在链接创建之后和链接关闭之前,可以执行用户自定义的函数。
  在IServer中添加四个函数。

    @abstractmethod
    def SetOnConnStart(self, cb):
        """
        设置该Server的连接创建时Hook函数
        :param cb:
        :return:
        """
        pass

    @abstractmethod
    def SetOnConnStop(self, cb):
        """
        设置该Server的连接断开时的Hook函数
        :param cb:
        :return:
        """
        pass

    @abstractmethod
    def CallOnConnStart(self, conn: IConnection):
        """
        调用连接OnConnStart Hook函数
        :param conn:
        :return:
        """
        pass

    @abstractmethod
    def CallOnConnStop(self, conn: IConnection):
        """
        调用连接OnConnStop Hook函数
        :param conn:
        :return:
        """
        pass

  在Server创建成员变量,将钩子函数定义一下。

class Server(IServer):
    def __init__(self, name: str, ip: str, port: int,
                 family: socket.AddressFamily = socket.AF_INET,
                 socket_kind: socket.SocketKind = socket.SOCK_STREAM):
        self.name: str = name
        self.family: socket.AddressFamily = family
        self.socket_kind: socket.SocketKind = socket_kind
        self.ip: str = ip
        self.port: int = port
        # self.Router: Optional[IRouter] = None
        self.msgHandler: IMsgHandler = NewMsgHandler()
        self.connManager: IConManager = NewConnManager()
        self.OnConnStart = None     # 函数类型  钩子函数
        self.OnConnStop = None      # 函数类型  钩子函数

  在Server创建函数,将钩子函数相关方法进行实现。

    def SetOnConnStart(self, cb):
        """
        设置该Server的连接创建时Hook函数
        :param cb: 函数类型
        :return:
        """
        self.OnConnStart = cb

    def SetOnConnStop(self, cb):
        """
        设置该Server的连接断开时的Hook函数
        :param cb:函数类型
        :return:
        """
        self.OnConnStop = cb

    def CallOnConnStart(self, conn: IConnection):
        """
        调用连接OnConnStart Hook函数
        :param conn:
        :return:
        """
        if self.OnConnStart:
            print("---> CallOnConnStart....")
            self.OnConnStart(conn)

    def CallOnConnStop(self, conn: IConnection):
        """
        调用连接OnConnStop Hook函数
        :param conn:
        :return:
        """
        if self.OnConnStop:
            print("---> CallOnConnStart....")
            self.OnConnStop(conn)

  在Connection中设置钩子函数的运行位置。也就是Start函数和Stop函数。

    def Start(self):
        """
        启动链接 让当前的链接准备开始工作
        :return:
        """
        print("链接开启,ID=", self.ConnID)
        # 开启写业务
        g1 = gevent.spawn(self.StartWriter)
        # 开启读业务
        g2 = gevent.spawn(self.StartReader)
        GlobalGevents.append(g1)
        GlobalGevents.append(g2)
        # 按照用户传递进来的创建连接时需要处理的业务,执行钩子方法
        self.TcpServer.CallOnConnStart(self)

    def Stop(self):
        """
        停止链接 结束当前链接的工作
        :return:
        """
        print("链接关闭,ID=", self.ConnID)
        if self.is_closed:
            return
        self.is_closed = True

        # 如果用户注册了该链接的关闭回调业务,那么在此刻应该显示调用
        self.TcpServer.CallOnConnStop(self)
        # 关闭socket链接,回收资源
        self.Conn.close()
        # 将链接从连接管理器中删除
        self.TcpServer.GetConnMgr().Remove(self)

  服务接口做完了。在demo\hook中做一个客户端和服务端测试一下。
  服务端代码。

# -*- coding: utf-8 -*-
import sys

sys.path.append("../../")
from znet.server import NewServer
from znet.router import BaseRouter
from ziface.irequest import IRequest


class PingRouter(BaseRouter):
    """
    用户自定义路由
    """

    def __init__(self):
        super().__init__()

    def Handle(self, request: IRequest):
        """
        处理conn业务的方法
        :param request:
        :return:
        """
        try:
            print("调用Handle")
            # request.GetConnection().GetTCPConnection().send("ping\n".encode("GB2312"))
            print(request.GetData())
            request.GetConnection().SendMsg(1, "ping\n".encode("GB2312"))
            request.GetConnection().SendMsg(1, request.GetData())
        except Exception as e:
            print("ping异常", e)


def ConnectionStart(con):
    print("======Start========", con.GetConnID())


def ConnectionStop(con):
    print("======Stop========", con.GetConnID())


if __name__ == '__main__':
    server = NewServer()
    server.AddRouter(1, PingRouter())
    server.SetOnConnStart(ConnectionStart)
    server.SetOnConnStop(ConnectionStop)
    server.Serve()

  客户端代码与demo\msghandler一样即可。
  此时发送和接收都正常。钩子模块完成。

上一篇下一篇

猜你喜欢

热点阅读