Python版本Zinx——(1)雏形

2023-08-25  本文已影响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)和第三方库来实现类似于接口的功能。在实际开发中,我们可以根据具体需求选择合适的实现方式。
  暂时使用抽象基类的形式模拟接口的实现。


  在ziface中创建iserver.py文件,里面做一个iserver的接口类。

# -*- coding: utf-8 -*-

from abc import ABC, abstractmethod

class IServer(ABC):
    """
    定义服务器接口
    """
    @abstractmethod
    def Start(self):
        """
        启动服务器方法
        :return:
        """
        pass

    @abstractmethod
    def Stop(self):
        """
         停止服务器方法
         :return:
         """
        pass

    @abstractmethod
    def Serve(self):
        """
        开启业务服务方法
        :return:
        """
        pass

  在znet中创建server.py文件,里面做一个IServer的实现类。

# -*- coding: utf-8 -*-
from typing import Optional
from ziface.iserver import IServer
from gevent import monkey
import time
import socket
import gevent
import signal
import sys


# 把内置阻塞的库替换成非阻塞的socket
monkey.patch_socket()
# 存一下协程
GlobalGevents: list = []


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

    def Start(self):
        """
        启动服务器方法
        :return:
        """
        print("[启动] 服务监听,IP地址:%s, 端口:%s,已经启动\n" % (self.ip, self.port))
        g1 = gevent.spawn(self.InitTCP)
        GlobalGevents.append(g1)

    def InitTCP(self):
        """
        初始化TCP链接
        :return:
        """
        # 1.获取一个TCP的Addr
        with socket.socket(self.family, self.socket_kind) as tcp:
            # 2.监听服务器的地址
            tcp.bind((self.ip, self.port))
            tcp.listen(128)
            print("[启动] %s服务启动成功,监听中......" % self.name)
            # 3.阻塞的等待客户端链接,处理客户端链接业务(读写)。
            while True:
                print("开启接收")
                remote_socket, remote_addr = tcp.accept()
                g2 = gevent.spawn(self.Echo(remote_socket, remote_addr))
                GlobalGevents.append(g2)

    def Echo(self, remote_socket, remote_addr):
        """
        回显功能
        :param remote_socket:
        :param remote_addr:
        :return:
        """
        print("链接开启", remote_addr)
        while True:
            try :
                read_buf = remote_socket.recv(512)
                print(read_buf)
                remote_socket.send(read_buf)
            except :
                continue

    def Stop(self):
        """
        停止服务器方法
        :return:
        """
        print("服务停止")

    def Serve(self):
        """
        开启业务服务方法
        :return:
        """
        self.Start()
        gevent.joinall(GlobalGevents)
        # 阻塞一下
        while True:
            time.sleep(10)


# 创建一个全局的server
m_server: Optional[IServer] = None


# 获取server
def NewServer() -> IServer:
    global m_server
    if m_server:
        return m_server
    m_server = Server("测试", "0.0.0.0", 8986)
    return m_server


# 接收停止信号,要不然报错看着烦
def signal_handler(signal, frame):
    global m_server
    m_server.Stop()
    print("程序已退出")
    sys.exit(0)


# 接收停止信号 ctrl+c
signal.signal(signal.SIGINT, signal_handler)

  写一个root.py的入口函数开启服务器。

from znet.server import NewServer

if __name__ == '__main__':
    server = NewServer()
    server.Serve()

  服务接口做完了,安装一个netcat做socket链接测试。在cmd中输入命令,回车

nc 127.0.0.1 8986

  输入几个字符,回车键发送,此时一个TCP的服务就已经开始运行了,回显功能可以正常运行。

上一篇 下一篇

猜你喜欢

热点阅读