Python版本Zinx——(7)讀寫分離

??最近想研究一下關(guān)于長鏈接的相關(guān)內(nèi)容,在B站上看到了Zinx框架的視頻,是Golang語言的框架,本著更好的理解框架的內(nèi)容,按照整個Zinx課程的進度,制作一個Python版本的Zinx框架。有關(guān)于Zinx框架的具體內(nèi)容,可以看框架作者的介紹
??python版本的Zinx,基于Gevent 22.10.2,使用協(xié)程功能。

??golang版本的Zinx項目,項目中兩個文件夾,ziface和znet。

  • ziface主要是存放一些Zinx框架的全部模塊的抽象層接口類。
  • znet模塊是zinx框架中網(wǎng)絡(luò)相關(guān)功能的實現(xiàn),所有網(wǎng)絡(luò)相關(guān)模塊都會定義在znet模塊中。
    └── zinx
    ?├── ziface
    ?│??└──
    ?└── znet
    ????├──

??python中的關(guān)鍵字沒有interface,但是可以使用抽象基類(abstract base class)和第三方庫來實現(xiàn)類似于接口的功能。在實際開發(fā)中,我們可以根據(jù)具體需求選擇合適的實現(xiàn)方式。
??暫時使用抽象基類的形式模擬接口的實現(xiàn)。


??在之前的章節(jié)中,消息讀到之后直接就進行了寫操作。本節(jié)就將寫操作分離出來。需要使用Queue隊列進行存儲即將需要寫的數(shù)據(jù)。本節(jié)內(nèi)容都在Connection中完成。
??在Connection中添加一個成員變量。

from gevent.queue import Queue


class Connection(IConnection):
    def __init__(self, conn: socket.socket, connID: int, remote_addr: tuple, msgHandler: IMsgHandler):
        self.Conn: socket.socket = conn  # 當前鏈接的socket TCP套接字
        self.ConnID: int = connID  # 鏈接的ID
        # self.HandlerAPI = handlerAPI  # 當前鏈接綁定的業(yè)務(wù)處理方法的API
        self.is_closed: bool = False  # 鏈接狀態(tài)
        self.Remote_Addr: tuple = remote_addr # 地址
        # self.Router: IRouter = router
        self.msgHandler: IMsgHandler = msgHandler # 消息處理模塊
        self.msgQueue: Queue = Queue() # 寫隊列

??修改一下SendMsg,原來的SendMsg直接就將消息寫出去了,現(xiàn)在需要將消息存入msgQueue中。

    def SendMsg(self, msgID: int, data: bytes):
        """
        發(fā)送數(shù)據(jù) 將數(shù)據(jù)發(fā)送給遠程的客戶端
        :param msgID:
        :param data:
        :return:
        """
        if self.is_closed:
            raise Exception("發(fā)送數(shù)據(jù)時客戶端鏈接被關(guān)閉")
        try:
            dp = NewDataPack()
            msg = dp.Pack(NewMessage(msgID, len(data), data))
            # self.Conn.send(msg)
            self.msgQueue.put(msg)
        except Exception as e:
            print(e)

??新增一個StartWriter函數(shù),實現(xiàn)寫功能。

    def StartWriter(self):
        """
        寫業(yè)務(wù)
        :return:
        """
        print("開啟寫業(yè)務(wù)")
        while True:
            try:
                if self.is_closed:
                    break
                msg = self.msgQueue.get_nowait()
                self.Conn.send(msg)
            except:
                # 由于msgQueue的get_nowait并不會主動切換其他協(xié)程,使用sleep切換到其他協(xié)程,保證不在當前協(xié)程中循環(huán)運行
                gevent.sleep(0)
                continue
        print(self.Remote_Addr, "寫業(yè)務(wù)退出")

??在Start函數(shù)中,開啟寫功能。

    def Start(self):
        """
        啟動鏈接 讓當前的鏈接準備開始工作
        :return:
        """
        print("鏈接開啟,ID=", self.ConnID)
        # 開啟寫業(yè)務(wù)
        g1 = gevent.spawn(self.StartWriter)
        # 開啟讀業(yè)務(wù)
        g2 = gevent.spawn(self.StartReader)
        GlobalGevents.append(g1)
        GlobalGevents.append(g2)

??服務(wù)接口做完了。在demo\read_write中做一個客戶端和服務(wù)端測試一下,代碼與demo\msghandler一樣即可。
??此時發(fā)送和接收都正常。讀寫分離完成。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容