Python websocket对象没有属性'write_message'错误

时间:2016-11-14 20:49:24

标签: python websocket tornado

我从here获得了python websocket客户端的示例代码,我遇到了下面的问题。自从我遇到问题以来,我在几个地方编辑了一些原始代码:

  • 删除了connect方法并将其合并到构造函数中。我曾是 找不到'self._ws_connection'问题。

  • 更改了WebSocketClient __init __()方法以接受'url' 并删除了''参数。我不确定传递''的是什么 装置

问题1:

Traceback (most recent call last):
  File "websocketcli.py", line 138, in <module>
    main()
  File "websocketcli.py", line 129, in main
    client.send('Hello world!')
  File "websocketcli.py", line 49, in send
    self._ws_connection.write_message(escape.utf8(json.dumps(data)))
  File "/users/anjangam/pyvenv/venv/lib/python2.7/site-packages/tornado/websocket.py", line 970, in write_message
    return self.protocol.write_message(message, binary)
AttributeError: 'NoneType' object has no attribute 'write_message'

问题2: 当我从WbSocketClient构造函数中删除'*'时,我得到以下错误,几乎与问题1中遇到的错误相同。注意:我使用的是python版本2.7.8。

Traceback (most recent call last):
  File "websocketcli.py", line 138, in <module>
    main()
  File "websocketcli.py", line 129, in main
    client.send('Hello world!')
  File "websocketcli.py", line 52, in send
    self._ws_connection.write_message(escape.utf8(json.dumps(data)))
  File "/users/anjangam/pyvenv/venv/lib/python2.7/site-packages/tornado/websocket.py", line 970, in write_message
    return self.protocol.write_message(message, binary)
AttributeError: 'NoneType' object has no attribute 'write_message'

客户代码:

from tornado import escape
from tornado import gen
from tornado import httpclient
from tornado import httputil
from tornado import ioloop
from tornado import websocket

import functools
import json
import time


APPLICATION_JSON = 'application/json'

DEFAULT_CONNECT_TIMEOUT = 60
DEFAULT_REQUEST_TIMEOUT = 60


class WebSocketClient():
"""Base for web socket clients.
"""
def __init__(self, connect_timeout=DEFAULT_CONNECT_TIMEOUT,
             request_timeout=DEFAULT_REQUEST_TIMEOUT):

    self.connect_timeout = connect_timeout
    self.request_timeout = request_timeout

def connect(self, url):
    """Connect to the server.
    :param str url: server URL.
    """
    headers = httputil.HTTPHeaders({'Content-Type': APPLICATION_JSON})
    request = httpclient.HTTPRequest(url=url,
                                     connect_timeout=self.connect_timeout,
                                     request_timeout=self.request_timeout,
                                     headers=headers)
    self._ws_connection = websocket.WebSocketClientConnection(ioloop.IOLoop.current(),
                                                  request)
    self._ws_connection.connect_future.add_done_callback(self._connect_callback)
    print 'Connection: ', self._ws_connection

    def send(self, data):
        """Send message to the server
        :param str data: message.
        """
        if not self._ws_connection:
            raise RuntimeError('Web socket connection is closed.')

        self._ws_connection.write_message(escape.utf8(json.dumps(data)))

    def close(self):
        """Close connection.
        """

        if not self._ws_connection:
            raise RuntimeError('Web socket connection is already closed.')

        self._ws_connection.close()

    def _connect_callback(self, future):
        if future.exception() is None:
            self._ws_connection = future.result()
            self._on_connection_success()
            self._read_messages()
        else:
            self._on_connection_error(future.exception())

    @gen.coroutine
    def _read_messages(self):
        while True:
            msg = yield self._ws_connection.read_message()
            if msg is None:
                self._on_connection_close()
                break

            self._on_message(msg)

    def _on_message(self, msg):
        """This is called when new message is available from the server.
        :param str msg: server message.
        """

        pass

    def _on_connection_success(self):
        """This is called on successful connection ot the server.
        """

        pass

    def _on_connection_close(self):
        """This is called when server closed the connection.
        """
        pass

    def _on_connection_error(self, exception):
        """This is called in case if connection to the server could
        not established.
        """

        pass


class TestWebSocketClient(WebSocketClient):

    def __init__(self, url):
        WebSocketClient.__init__(self, url)

    def _on_message(self, msg):
        print(msg)
        deadline = time.time() + 1
        ioloop.IOLoop().instance().add_timeout(
            deadline, functools.partial(self.send, str(int(time.time()))))

    def _on_connection_success(self):
        print('Connected!')
        self.send(str(int(time.time())))

    def _on_connection_close(self):
        print('Connection closed!')

    def _on_connection_error(self, exception):
        print('Connection error: %s', exception)


def main():
    client = TestWebSocketClient()
    client.connect('ws://localhost:8888/ws')
    client.send('Hello world!')


    try:
        ioloop.IOLoop.instance().start()
    except KeyboardInterrupt:
        client.close()


if __name__ == '__main__':
    main()

1 个答案:

答案 0 :(得分:1)

你引用的原始代码在python 3.5上运行得很好,但是我怀疑你使用的是某些版本的python 2.它会破坏的原因是你提到的星号,这不是python 2的一个特性。 PEP 3102谈到这一点,但简而言之,星号将强制函数调用传递关键字参数,而不是依赖于提供参数的顺序。

因此,例如以下函数:

# we can use positional arguments on this one
def test(a, b):
    print(a, b)

# this will require keyword arguments to be supplied on function calls
def test_keywords_args_required(*, a, b):
    print(a, b)

test(1, 2) # test can be called using positional arguments
test_keywords_args_required(1, 2) # this will error out. Needs keywords args!
test_keywords_args_required(a=1, b=2) # this will work!

如果您使用最初从该链接提供的代码,并删除星号,则代码应该有效(使用python 2.7确认)。