简体   繁体   English

在 python 中使用 websocket 客户端作为类

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

I'm trying access some data using websockets, but I cannot really get around the examples given in the websockets documentation.我正在尝试使用 websockets 访问一些数据,但我无法真正绕过 websockets 文档中给出的示例。

I have this code ( https://pypi.org/project/websocket_client/ ) and want to transform it into a class.我有这个代码( 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()

The idea is to have this all websocket functionality in a class so that I can just create an object of that class.这个想法是在一个类中拥有所有这些 websocket 功能,这样我就可以创建该类的一个对象。

I tried to start doing it but I cannot even get passed this:我试图开始这样做,但我什至无法通过这个:

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)

The error starts right away in on_message saying that's an "unresolved reference".错误立即在on_message开始,说这是一个“未解析的引用”。

Package the call inside an anonymous lambda function to achieve a proper call with the correct self :将调用打包在匿名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)
    ...

The WebSocketApp needs callable objects for its callbacks (both the ones you pass in the constructor, like on_message , and the one you're setting after the fact, on_open ). WebSocketApp的回调需要可调用对象(您在构造函数中传递的对象,如on_message ,以及事后设置的对象, on_open )。

Plain functions are callable objects, so your non-OO version works fine, because you're passing the plain functions.普通函数是可调用对象,因此您的非 OO 版本可以正常工作,因为您正在传递普通函数。

Bound methods are also callable objects.绑定方法也是可调用对象。 But your OO version isn't passing bound methods.但是您的 OO 版本没有传递绑定方法。 A bound method is, as the name implies, bound to an object.绑定方法,顾名思义,绑定到一个对象。 You do this by using the obj.method notation.您可以使用obj.method表示法来完成此操作。 In your case, that's self.on_message :在你的情况下,那是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

However, you've got another problem.但是,您还有另一个问题。 While this will make your error go away, it won't make your code actually work.虽然这会使您的错误消失,但不会使您的代码真正工作。 A normal method has to take self as its first argument:一个普通的方法必须将self作为它的第一个参数:

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

It's also worth noting that you're not really using the class for anything.另外值得一提的是,你没有真正使用类的东西。 If you never access anything off self , the class is just acting like a namespace.如果您从不访问self任何内容,则该类就像一个命名空间。 Not that this is always a bad thing, but it's usually a sign that you need to at least think through your design.并不是说这总是一件坏事,但这通常表明您至少需要仔细考虑您的设计。 Is there really any state that you need to maintain?真的有任何需要维护的状态吗? If not, why do you want a class in the first place?如果没有,你为什么首先要上课?

You may want to reread the tutorial section on Classes to understand about methods, self , etc.您可能需要重新阅读有关类教程部分以了解方法、 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()

I wonder why everyone is still putting the ws parameter.不知道为什么大家还在放ws参数。

Read the error log.阅读错误日志。

File "venv/lib/python3.7/site-packages/websocket/_app.py", line 343, in _callback callback(*args)文件“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)

Looking at our callbacks, on_open(self, ws)查看我们的回调, on_open(self, ws)

When the try block executes it checks if our callback is a method or a function.try块执行时,它会检查我们的回调是一个方法还是一个函数。 if it is a method it would execute the callback(*args) already our self from our CustomClient is already passed as an argument in (*args).如果它是一个方法,它将执行callback(*args)已经我们的自定义客户端中的CustomClient已经作为参数传递给 (*args)。 Mind you it already has its own self in def _callback(self, callback, *args) .请注意,它已经在def _callback(self, callback, *args)拥有自己的self Hence, every callback that is an instance of your CustomClient should not have the ws argument.因此,作为CustomClient实例的每个回调CustomClient应该有 ws 参数。

You need to add "self" to you class methods:您需要在类方法中添加“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)

The Self makes those methods as Class methods , Got this one working as the on_error/message/close methods signature will get satisfied if called by self as will refer to the class itself . 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()

Just updating the code written by other authors on this page, that worked for me.只需更新此页面上其他作者编写的代码,这对我有用。 The problem is that in the event callback functions definition like on_message we should not use ws as parameter.问题是在像 on_message 这样的事件回调函数定义中,我们不应该使用 ws 作为参数。 self takes care of it and in the body of these event handler functions we should use self.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")

I would like try this way:我想试试这种方式:

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

Using inner function in method __init__(self) could avoid the problem that the arguments number of on_message(self, ws, message) method not match with the number of WebSocketApp provides to its argument on_message (class method has one more argument self ).在方法__init__(self)使用内部函数可以避免on_message(self, ws, message)方法的参数数量与WebSocketApp提供给其参数on_message的数量不匹配的on_message (类方法多了一个参数self )。

I have a handler above to handle the message, method close(self) to clean some resources if I have, run_forever(self) to run websocket.我上面有一个handler来处理消息,如果有的话,方法close(self)来清理一些资源, run_forever(self)来运行 websocket。

This is working:这是有效的:

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)

But you don't have access to self但你无权访问 self

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM