簡體   English   中英

在 python 中使用 websocket 客戶端作為類

[英]Using a websocket client as a class in python

我正在嘗試使用 websockets 訪問一些數據,但我無法真正繞過 websockets 文檔中給出的示例。

我有這個代碼( https://pypi.org/project/websocket_client/ )並想將它轉換成一個類。

import websocket
import thread
import time

def on_message(ws, message):
    print message

def on_error(ws, error):
    print error

def on_close(ws):
    print "### closed ###"

def on_open(ws):
    def run(*args):
        for i in range(3):
            time.sleep(1)
            ws.send("Hello %d" % i)
        time.sleep(1)
        ws.close()
        print "thread terminating..."
    thread.start_new_thread(run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                on_message = on_message,
                                on_error = on_error,
                                on_close = on_close)
    ws.on_open = on_open

    ws.run_forever()

這個想法是在一個類中擁有所有這些 websocket 功能,這樣我就可以創建該類的一個對象。

我試圖開始這樣做,但我什至無法通過這個:

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                    on_message = on_message,
                                    on_error = on_error,
                                    on_close = on_close)

    def on_message(ws, message):
        print message

    def on_error(ws, error):
        print error

    def on_close(ws):
        print "### closed ###"

    def on_open(ws):
    ws.send("Hello %d" % i)

錯誤立即在on_message開始,說這是一個“未解析的引用”。

將調用打包在匿名lambda函數中,以使用正確的self實現正確調用:

class Client:
    def __init__(self, db, symbols):
        self.ws = websocket.WebSocketApp("wss://the.server.com/api",
                    on_message = lambda ws,msg: self.on_message(ws, msg),
                    on_error   = lambda ws,msg: self.on_error(ws, msg),
                    on_close   = lambda ws:     self.on_close(ws),
                    on_open    = lambda ws:     self.on_open(ws))

    def on_message(self, ws, message):
            msg = json.loads(message)
            print(msg)
    ...

WebSocketApp的回調需要可調用對象(您在構造函數中傳遞的對象,如on_message ,以及事后設置的對象, on_open )。

普通函數是可調用對象,因此您的非 OO 版本可以正常工作,因為您正在傳遞普通函數。

綁定方法也是可調用對象。 但是您的 OO 版本沒有傳遞綁定方法。 綁定方法,顧名思義,綁定到一個對象。 您可以使用obj.method表示法來完成此操作。 在你的情況下,那是self.on_message

self.ws = websocket.WebSocketApp("ws://echo.websocket.org/",
                                 on_message = self.on_message,
                                 on_error = self.on_error,
                                 on_close = self.on_close)
self.ws.on_open = self.on_open

但是,您還有另一個問題。 雖然這會使您的錯誤消失,但不會使您的代碼真正工作。 一個普通的方法必須將self作為它的第一個參數:

def on_message(self, ws, message):
    print message

另外值得一提的是,你沒有真正使用類的東西。 如果您從不訪問self任何內容,則該類就像一個命名空間。 並不是說這總是一件壞事,但這通常表明您至少需要仔細考慮您的設計。 真的有任何需要維護的狀態嗎? 如果沒有,你為什么首先要上課?

您可能需要重新閱讀有關類教程部分以了解方法、 self等。

import websocket

try:
    import thread
except ImportError:
    import _thread as thread
import time


class OnyxGenericClient:
    """
    Onyx Client Interface

    """

    def __init__(self, ):
        websocket.enableTrace(True)
        ws = websocket.WebSocketApp("ws://localhost:3000/",
                                         on_message=self.on_message,
                                         on_error=self.on_error,
                                         on_close=self.on_close)
        self.ws = ws
        self.ws.on_open = self.on_open
        self.ws.run_forever()

    # def initiate(self):

    def on_message(self, message):
        print(message)
        return message

    def on_error(self, error):
        return error

    def on_close(self):
        print("### closed ###")

    def run(self, *args):
        global driver
        driver = True
        while driver:
            try:
                time.sleep(1)
                print("Say something nice")
                p = input()
                self.ws.send(p)
            except KeyboardInterrupt:
                driver = False
        time.sleep(1)
        self.ws.close()
        print("thread terminating...")

    def on_open(self):
        thread.start_new_thread(self.run, ())


if __name__ == "__main__":
    websocket.enableTrace(True)
    onyx_client = OnyxGenericClient()

不知道為什么大家還在放ws參數。

閱讀錯誤日志。

文件“venv/lib/python3.7/site-packages/websocket/_app.py”,第 343 行,在 _callback 回調(*args)中

    def _callback(self, callback, *args):
    if callback:
        try:
            if inspect.ismethod(callback):
                callback(*args)
            else:
                callback(self, *args)

        except Exception as e:
            _logging.error("error from callback {}: {}".format(callback, e))
            if _logging.isEnabledForDebug():
                _, _, tb = sys.exc_info()
                traceback.print_tb(tb)

查看我們的回調, on_open(self, ws)

try塊執行時,它會檢查我們的回調是一個方法還是一個函數。 如果它是一個方法,它將執行callback(*args)已經我們的自定義客戶端中的CustomClient已經作為參數傳遞給 (*args)。 請注意,它已經在def _callback(self, callback, *args)擁有自己的self 因此,作為CustomClient實例的每個回調CustomClient應該有 ws 參數。

您需要在類方法中添加“self”:

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                on_message = self.on_message,
                                on_error = self.on_error,
                                on_close = self.on_close)

    def on_message(self, ws, message):
        print message

    def on_error(self, ws, error):
        print error

    def on_close(self, ws):
        print "### closed ###"

    def on_open(self, ws):
        ws.send("Hello %d" % i)

Self 將這些方法作為類方法,得到這個作為 on_error/message/close 方法簽名將得到滿足,如果由 self 調用將引用類本身。

 class MySocket(object):
   def __init__(self,x):
     websocket.enableTrace(True)
     ## Only Keep the object Initialisation here  
     self.x=x
     self.ws=None

     # call This method from a Object and it will create and run the websocket 
    def ws_comm(self):
        self.ws = websocket.WebSocketApp(self.WS_URL,on_message = 
        self.on_message,on_error =self.on_error,on_close = self.on_close)
        self.ws.on_open = self.on_open
        self.ws.run_forever()

    def on_error(self,ws, error):
        print "onError", error

    def on_close(self,ws):
       print "onClosed"

    #Send some message on open 
    def on_open(self,ws):
       self.ws.send(json.dumps(register_msg))

    def on_message(self,ws, msg):
       self.ws.send(json.dumps(msg))


 user1=Userapp('x')
 user1.ws_comm()

只需更新此頁面上其他作者編寫的代碼,這對我有用。 問題是在像 on_message 這樣的事件回調函數定義中,我們不應該使用 ws 作為參數。 self 負責它,在這些事件處理函數的主體中,我們應該使用 self.ws

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                on_message = self.on_message,
                                on_error = self.on_error,
                                on_close = self.on_close)

    
    def on_message(self, message):
        # if you want to send something use like this
        # self.ws.send()
        print message

    def on_error(self, error):
        print error

    def on_close(self):
        print "### closed ###"

    def on_open(self):
        self.ws.send("Hello Message")

我想試試這種方式:

class FooClient(object):
    def __init__(self):
        def on_message(ws, message):
            print message
            # use 'self' variable to access other resource
            # handle message from websocket server like this
            self.handler.handle(message)

        def on_error(ws, error):
            print error

        def on_close(ws):
            print "### closed ###"

        def on_open(ws):
            ws.send("Hello %d" % i)

        # assign to 'self.handler'
        self.handler = FooHandler()
        # maybe there are another module should be initiated
        # ...

        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                         on_message = on_message,
                                         on_error = on_error,
                                         on_close = on_close)

    def run_forever(self):
        self.ws.run_forever()

    def close(self):
        """clean other resources"""
        pass

在方法__init__(self)使用內部函數可以避免on_message(self, ws, message)方法的參數數量與WebSocketApp提供給其參數on_message的數量不匹配的on_message (類方法多了一個參數self )。

我上面有一個handler來處理消息,如果有的話,方法close(self)來清理一些資源, run_forever(self)來運行 websocket。

這是有效的:

class MySocket(object):
    def __init__(self):
        websocket.enableTrace(True)
        self.ws = websocket.WebSocketApp("ws://echo.websocket.org:12300/foo",
                                on_message = self.on_message,
                                on_error = self.on_error,
                                on_close = self.on_close)

    @staticmethod
    def on_message(ws, message):
        print message

    @staticmethod
    def on_error(ws, error):
        print error

    @staticmethod
    def on_close(ws):
        print "### closed ###"

    @staticmethod
    def on_open(ws):
        ws.send("Hello %d" % i)

但你無權訪問 self

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM