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:
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:
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上一篇: 直观的方式来查看最活跃的分叉