Tornado websockets supporting binary part 2

I am attempting to pass binary data over websockets, more specifically compressed strings over websockets. In my current setup I use tornado as the server with a websocket client transmitting the binary data. The binary data is formed by compressing the data with zlib . Both client and server are as simple as they get and are shown below.

Server:

import tornado.websocket
import tornado.httpserver
import tornado.ioloop
import tornado.web

class WebSocketServer(tornado.websocket.WebSocketHandler):
    def open(self):
        print 'OPEN'

    def on_message(self, message):
        print 'len = {}'.format(len(message))
        print 'GOT MESSAGE: {}'.format(message.decode('zlib'))

    def on_close(self):
        print 'CLOSE'

app = tornado.web.Application([
        (r'/', WebSocketServer)
    ])
http_server = tornado.httpserver.HTTPServer(app)
http_server.listen(9500)
tornado.ioloop.IOLoop.instance().start()

Client:

import websocket

host = 'localhost'
port_ws = 9500
ws = websocket.create_connection('ws://{}:{}/'.format(host, port_ws))
message = 'this is my message'.encode('zlib')
print 'Length of message is {}'.format(len(message))
ws.send(message)

The client does not throw any errors, it prints out that the message: Length of message is 24 . The message is encoded as a str as per the zlib standard. The server on the other end does not show that it received any messages, it just understands that a client had connected, and then disconnected. Does anyone know where the problem is? I am not sure if the problem lays within tornado or the websockets library. Any suggestions?


EDIT: In response to the comment below (@plg), I modified the scripts above to show that:

  • Non-encoded messages can be send from client to the tornado server
  • Tornado can reply with an encoded message
  • Server:

    import tornado.websocket
    import tornado.httpserver
    import tornado.ioloop
    import tornado.web
    
    class WebSocketServer(tornado.websocket.WebSocketHandler):
        def open(self):
            print 'OPEN'
    
        def on_message(self, message):
            print 'len = {}'.format(len(message))
            print 'GOT MESSAGE: {}'.format(message)
            self.write_message(message.encode('zlib'))
    
        def on_close(self):
            print 'CLOSE'
    
    app = tornado.web.Application([
            (r'/', WebSocketServer)
        ])
    http_server = tornado.httpserver.HTTPServer(app)
    http_server.listen(9500)
    tornado.ioloop.IOLoop.instance().start()
    

    Client:

    import websocket
    
    host = 'localhost'
    port_ws = 9500
    ws = websocket.create_connection('ws://{}:{}/'.format(host, port_ws))
    #message = 'this is my message'.encode('zlib')
    message = 'this is my message'
    print 'Length of message is {}'.format(len(message))
    ws.send(message)
    assert ws.recv().decode('zlib') == message
    

    The system works just fine. The assert does not throw an error. The decoded message matches the send message. So I guess there is a problem with either:

  • Sending an encoded message from the client
  • Tornado receiving encoded messages
  • To be quite honest, I do believe that the first option is more probable than tornado. In my opinion, I believe tornado would alert me if an incoming message is not properly decoded as per the websocket standard. Any more suggestions?


    EDIT: More development on who is at fault. Instead of using my own server to relay back and fourth my connection, I relayed the connection to ws://echo.websocket.org/ . My testing application is as shows:

    import websocket
    
    host = 'localhost'
    port_ws = 9500
    ws = websocket.create_connection('ws://echo.websocket.org/')
    message = 'this is my message'
    ws.send(message.encode('zlib'))
    got = ws.recv().decode('zlib')
    print 'GOT: {}'.format(got)
    assert got == message
    

    This actually passed the test, the data was received just fine. So I guess there is something wrong with tornado receiving the data?


    After looking though the source code of the websocket library, I found that by default it is formatting the packets as text. By changing the line:

    ws.send('message')
    # to:
    ws.send('message', opcode=websocket.ABNF.OPCODE_BINARY)
    # or better yet:
    ws.send_binary('message')
    

    The packet will be sent over just fine. Tornado I guess was just ignoring the fake binary packets since they were marked as text and contained binary.


    感谢这个提交龙卷风支持websocket压缩扩展。

    链接地址: http://www.djcxy.com/p/74490.html

    上一篇: 直观的方式来查看最活跃的分叉

    下一篇: 支持二进制部分2的龙卷风websockets