ws4py - send/received_message 不工作
ws4py - send/received_message not working
我在制作 WebSocket 时遇到问题 Server/Client。
这是我的 WebSocket 类:
wslist = []
class LoginLiveWebSocketHandler(WebSocket): # /live/ws/zones
loggedon = False
def opened(self):
log("Opened!")
wslist.append(self)
def received_message(self, m):
log("Received Message!")
log(m)
log(m.data)
m = str(m.data)
if not m.startswith("Login: ") & (not self.loggedon):
return
if m.startswith("Login: ") & self.loggedon:
return
if m.startswith("Login: ") & (not self.loggedon):
split = m.replace("Login: ", "").split(":")
try:
id = split[0]
key = split[1]
except KeyError:
self.send("Login: 0", False)
return
try:
usr = users.getuser(id, key)
nick = usr["nick"]
loggedin = True
token = usr["groupme_token"]
active = usr["active"]
except KeyError or TypeError:
self.send("Login: 0", False)
return
if (not loggedin) | (not active) | (not local.token) | (local.user["faction"] != "f"):
self.send("Login: 0", False)
return
self.send("Login: 1", False)
self.loggedon = True
return
def closed(self, code, reason=""):
log("Closed!")
wslist.remove(self)
还有我的 JavaScript 页面(注意,不是全部):
function init() {
showBlocking("Connecting...", "progress-bar-success");
var wsprotocol = (location.protocol == "https:") ? "wss://" : "ws://";
var loc = location.pathname;
loc = loc.replace(/live\u002flive$/i, "");
var wsurl = wsprotocol + location.host + loc + "/live/ws_zones";
console.log(wsurl);
var ws = new WebSocket(wsurl);
var key = getCookie("key");
var id = getCookie("id");
var closed = true;
ws.onopen = function(evt) {
console.log("onopen");
$('#pbheader').text("Logging in...");
ws.send("Login: " + id + ":" + key);
closed = false;
}
ws.onmessage = function(evt) {
console.log("OnMessage");
var channel = evt.data.substring(0, 7);
var data = evt.data.substr(6);
if (channel == "Login: ") {
if (data == "0") {
ws.close();
closed = true;
alert("Invalid Login, please re-login.");
$('#pbheader').text("Invalid Login!");
history.back();
} else if (data == "1") {
hideBlocking();
}
} else if (channel == "ZoneA: ") {
// add new thing...
// %gridref% %zoneid% %zonename% %faction% %legion% %faceless% %swarm%
var datadict = JSON.parse(data);
var replitem = itemtemplate.replace("%count%", count).replace("%gridref%", datadict.gridref).replace("%zoneid%", datadict.zoneid).replace("%zonename%", datadict.zonename).replace("%faction%", datadict.faction).replace("%legion%", datadict.legion).replace("%faceless%", datadict.faceless).replace("%swarm%", datadict.swarm);
$('#live').prepend(replitem);
var curritem = $('#item' + count);
setTimeout(function () { fadeoutremove(curritem); }, 60*1000);
count = count + 1;
}
}
ws.onclose = function(evt) {
console.log("Closed");
closed = true;
}
ws.onerror = function(evt) {
console.log("error");
closed = true;
}
}
window.addEventListener("load", init, false);
安装服务:
log("Starting WebServer (cherrypy)")
cherrypy.server.unsubscribe()
if config.DO_SSL is True:
server1 = cherrypy._cpserver.Server()
server1.socket_port = config.LISTEN_PORT_SSL
server1._socket_host = config.LISTEN
server1.thread_pool = 30
server1.ssl_certificate = config.SSL_CERTIFICATE
server1.ssl_private_key = config.SSL_PRIVATE_KEY
server1.ssl_certificate_chain = config.SSL_CHAIN
server1.ssl_module = config.SSL_HANDLER
server1.subscribe()
server2 = cherrypy._cpserver.Server()
server2.socket_port = config.LISTEN_PORT
server2._socket_host = config.LISTEN
server2.thread_pool = 30
server2.subscribe()
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()
cherrypy.tree.mount(APIService.APIService(), "/api", config={"/": {'error_page.404': APIService.ep}})
cherrypy.tree.mount(JSONService.JSONService(), "/json", config={"/": {'error_page.404': JSONService.ep}})
cherrypy.tree.mount(USRAPIService.USRAPIService(), "/usrapi", config={"/": {'error_page.404': USRAPIService.ep}})
cherrypy.tree.mount(USRAPIAdminService.USRAPIAdminService(), "/usrapi/admin", config={
"/": {'error_page.404': USRAPIService.ep}})
cherrypy.tree.mount(RootService.RootService(), "/", config={"/": {'error_page.404': RootService.ep}})
cherrypy.tree.mount(AdminService.AdminService(), "/admin", config={"/": {'error_page.404': AdminService.ep}})
cherrypy.tree.mount(HelperPanel.HelperPanel(), "/helper", config={"/": {'error_page.404': HelperPanel.ep}})
cherrypy.tree.mount(LiveService.LiveService(), "/live", config={"/": {'error_page.404': LiveService.ep},
"/ws_zones": {'tools.websocket.on': True,
'tools.websocket.handler_cls':
LiveService.LoginLiveWebSocketHandler
}})
cherrypy.tree.mount(None, "/static", config={"/": {'error_page.404': AdminService.ep,
'tools.staticdir.on': True,
'tools.staticdir.dir':
os.path.join(__current_dir, "web/static")}})
cherrypy.engine.start()
log("Started WebServer (cherrypy)")
直播服务:
class LiveService(object):
@cherrypy.expose
@require(level=0)
def index(self, user, usrname, usrhelper, usradmin):
return render("index", usrname, usrhelper, usradmin)
@cherrypy.expose
@require(level=4) # Require login, Groupme, active and faceless
def live(self, user, usrname, usrhelper, usradmin):
return render("websocket/zonesdata", usrname, usrhelper, usradmin)
@cherrypy.expose
def ws_zones(self):
log("Handler created: %s" % repr(cherrypy.request.ws_handler))
cherrypy.request.ws_handler.send(b"Login 0", False)
因此,安装和启动工作正常,整个 运行 已经投入生产几个月了,但是带有 ws 的新 LiveService 不工作。
在日志中,我收到 [21/Jul/2015:16:55:28] ENGINE Starting WebSocket processing
和 Opened
消息,但我从未收到或无法发送消息。
当我将 LiveService.LoginLiveServiceWebSocketHandler 更改为 EchoWebSocket 时,他会收到消息并发送它们,但是在 ws_zones 处理程序
cherrypy.request.ws_handler.send(b"Login 0", 假)
不工作。带不带b.
分析
首先要说的是,您应该注意您可以使用的调试工具。例如,当您在 Firefox 中尝试您的应用程序时,Firebug(或 Web 控制台)会告诉您:
Firefox can't establish a connection to the server at ws://127.0.0.1:8080/live/ws_zones.
Chromium 控制台有更多有用的错误消息:
WebSocket connection to 'ws://127.0.0.1:8080/live/ws_zones' failed: Error during WebSocket handshake: Invalid status line
好的,我们有一个握手问题。
如果你打开 Wireshark(或其他嗅探器),你可以看到我们的 Login 0
确实出现在 ws4py
以握手响应(或者可能存在竞争条件)的回复之前。
我能理解你的困惑,因为在几个地方 ws4py
文档要么暗示要么直接引导你错误的方式。让我们看看:
alludes — 您不能从普通处理程序发送。
@cherrypy.expose
def ws(self):
# you can access the class instance through
handler = cherrypy.request.ws_handler
guides incorrectly — 你不能从 opened
挂钩发送。
def opened(self):
"""
Called by the server when the upgrade handshake
has succeeeded.
"""
pass
所以我认为这是过时的文档或错误。
解决方案
现在我建议您在客户端发起通信。如果你有一些预登录 "chat",你可以在网络套接字之上做一个小协议(无论如何你最终都会这样做)。像这样:
#!/usr/bin/env python3
import json
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
class LoginLiveWebSocketHandler(WebSocket):
wsset = set()
'''Class level attr, do not rebind'''
def opened(self):
'''You can not send yet, because handshake has not been completed.
Yes, a documentation is not always correct ;-)
'''
cherrypy.log('Opened!')
self.wsset.add(self)
def closed(self, code, reason = ''):
cherrypy.log('Closed!')
self.wsset.remove(self)
def received_message(self, message):
cherrypy.log('Received Message!')
message = json.loads(message.data.decode())
if message['cmd'] == 'init':
self.send('Login 0')
else:
self.send(message['payload'] + ' pong')
class LiveService(object):
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<body>
<div id='log'></div>
<script type='application/javascript'>
var ws = new WebSocket('ws://127.0.0.1:8080/live/ws_zones');
ws.onopen = function(event)
{
ws.send(JSON.stringify({'cmd': 'init'}));
};
ws.onmessage = function(event)
{
document.getElementById('log').innerHTML += event.data + '<br/>';
};
var handle = setInterval(function()
{
if(ws.readyState == WebSocket.CLOSING || ws.readyState == WebSocket.CLOSED)
{
clearInterval(handle);
}
else
{
ws.send(JSON.stringify({'cmd': 'chat', 'payload': 'ping'}));
}
}, 1000);
</script>
</body>
</html>
'''
@cherrypy.expose
def ws_zones(self):
'''You can not send yet, because handshake has not been completed'''
cherrypy.log('Handler created: %r' % cherrypy.request.ws_handler)
if __name__ == '__main__':
cherrypy.config.update({
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
})
cherrypy.tools.websocket = WebSocketTool()
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tree.mount(LiveService(), '/live', {
'/ws_zones' : {
'tools.websocket.on' : True,
'tools.websocket.handler_cls' : LoginLiveWebSocketHandler
}
})
cherrypy.engine.signals.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
有点傻...
@saaj 是对的,但真正的问题是我试图用 m、m.data 等调用函数 log(需要 str)。使用 repr() 或删除它来执行此操作,它有效!
谢谢!
我在制作 WebSocket 时遇到问题 Server/Client。
这是我的 WebSocket 类:
wslist = []
class LoginLiveWebSocketHandler(WebSocket): # /live/ws/zones
loggedon = False
def opened(self):
log("Opened!")
wslist.append(self)
def received_message(self, m):
log("Received Message!")
log(m)
log(m.data)
m = str(m.data)
if not m.startswith("Login: ") & (not self.loggedon):
return
if m.startswith("Login: ") & self.loggedon:
return
if m.startswith("Login: ") & (not self.loggedon):
split = m.replace("Login: ", "").split(":")
try:
id = split[0]
key = split[1]
except KeyError:
self.send("Login: 0", False)
return
try:
usr = users.getuser(id, key)
nick = usr["nick"]
loggedin = True
token = usr["groupme_token"]
active = usr["active"]
except KeyError or TypeError:
self.send("Login: 0", False)
return
if (not loggedin) | (not active) | (not local.token) | (local.user["faction"] != "f"):
self.send("Login: 0", False)
return
self.send("Login: 1", False)
self.loggedon = True
return
def closed(self, code, reason=""):
log("Closed!")
wslist.remove(self)
还有我的 JavaScript 页面(注意,不是全部):
function init() {
showBlocking("Connecting...", "progress-bar-success");
var wsprotocol = (location.protocol == "https:") ? "wss://" : "ws://";
var loc = location.pathname;
loc = loc.replace(/live\u002flive$/i, "");
var wsurl = wsprotocol + location.host + loc + "/live/ws_zones";
console.log(wsurl);
var ws = new WebSocket(wsurl);
var key = getCookie("key");
var id = getCookie("id");
var closed = true;
ws.onopen = function(evt) {
console.log("onopen");
$('#pbheader').text("Logging in...");
ws.send("Login: " + id + ":" + key);
closed = false;
}
ws.onmessage = function(evt) {
console.log("OnMessage");
var channel = evt.data.substring(0, 7);
var data = evt.data.substr(6);
if (channel == "Login: ") {
if (data == "0") {
ws.close();
closed = true;
alert("Invalid Login, please re-login.");
$('#pbheader').text("Invalid Login!");
history.back();
} else if (data == "1") {
hideBlocking();
}
} else if (channel == "ZoneA: ") {
// add new thing...
// %gridref% %zoneid% %zonename% %faction% %legion% %faceless% %swarm%
var datadict = JSON.parse(data);
var replitem = itemtemplate.replace("%count%", count).replace("%gridref%", datadict.gridref).replace("%zoneid%", datadict.zoneid).replace("%zonename%", datadict.zonename).replace("%faction%", datadict.faction).replace("%legion%", datadict.legion).replace("%faceless%", datadict.faceless).replace("%swarm%", datadict.swarm);
$('#live').prepend(replitem);
var curritem = $('#item' + count);
setTimeout(function () { fadeoutremove(curritem); }, 60*1000);
count = count + 1;
}
}
ws.onclose = function(evt) {
console.log("Closed");
closed = true;
}
ws.onerror = function(evt) {
console.log("error");
closed = true;
}
}
window.addEventListener("load", init, false);
安装服务:
log("Starting WebServer (cherrypy)")
cherrypy.server.unsubscribe()
if config.DO_SSL is True:
server1 = cherrypy._cpserver.Server()
server1.socket_port = config.LISTEN_PORT_SSL
server1._socket_host = config.LISTEN
server1.thread_pool = 30
server1.ssl_certificate = config.SSL_CERTIFICATE
server1.ssl_private_key = config.SSL_PRIVATE_KEY
server1.ssl_certificate_chain = config.SSL_CHAIN
server1.ssl_module = config.SSL_HANDLER
server1.subscribe()
server2 = cherrypy._cpserver.Server()
server2.socket_port = config.LISTEN_PORT
server2._socket_host = config.LISTEN
server2.thread_pool = 30
server2.subscribe()
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()
cherrypy.tree.mount(APIService.APIService(), "/api", config={"/": {'error_page.404': APIService.ep}})
cherrypy.tree.mount(JSONService.JSONService(), "/json", config={"/": {'error_page.404': JSONService.ep}})
cherrypy.tree.mount(USRAPIService.USRAPIService(), "/usrapi", config={"/": {'error_page.404': USRAPIService.ep}})
cherrypy.tree.mount(USRAPIAdminService.USRAPIAdminService(), "/usrapi/admin", config={
"/": {'error_page.404': USRAPIService.ep}})
cherrypy.tree.mount(RootService.RootService(), "/", config={"/": {'error_page.404': RootService.ep}})
cherrypy.tree.mount(AdminService.AdminService(), "/admin", config={"/": {'error_page.404': AdminService.ep}})
cherrypy.tree.mount(HelperPanel.HelperPanel(), "/helper", config={"/": {'error_page.404': HelperPanel.ep}})
cherrypy.tree.mount(LiveService.LiveService(), "/live", config={"/": {'error_page.404': LiveService.ep},
"/ws_zones": {'tools.websocket.on': True,
'tools.websocket.handler_cls':
LiveService.LoginLiveWebSocketHandler
}})
cherrypy.tree.mount(None, "/static", config={"/": {'error_page.404': AdminService.ep,
'tools.staticdir.on': True,
'tools.staticdir.dir':
os.path.join(__current_dir, "web/static")}})
cherrypy.engine.start()
log("Started WebServer (cherrypy)")
直播服务:
class LiveService(object):
@cherrypy.expose
@require(level=0)
def index(self, user, usrname, usrhelper, usradmin):
return render("index", usrname, usrhelper, usradmin)
@cherrypy.expose
@require(level=4) # Require login, Groupme, active and faceless
def live(self, user, usrname, usrhelper, usradmin):
return render("websocket/zonesdata", usrname, usrhelper, usradmin)
@cherrypy.expose
def ws_zones(self):
log("Handler created: %s" % repr(cherrypy.request.ws_handler))
cherrypy.request.ws_handler.send(b"Login 0", False)
因此,安装和启动工作正常,整个 运行 已经投入生产几个月了,但是带有 ws 的新 LiveService 不工作。
在日志中,我收到 [21/Jul/2015:16:55:28] ENGINE Starting WebSocket processing
和 Opened
消息,但我从未收到或无法发送消息。
当我将 LiveService.LoginLiveServiceWebSocketHandler 更改为 EchoWebSocket 时,他会收到消息并发送它们,但是在 ws_zones 处理程序
cherrypy.request.ws_handler.send(b"Login 0", 假)
不工作。带不带b.
分析
首先要说的是,您应该注意您可以使用的调试工具。例如,当您在 Firefox 中尝试您的应用程序时,Firebug(或 Web 控制台)会告诉您:
Firefox can't establish a connection to the server at ws://127.0.0.1:8080/live/ws_zones.
Chromium 控制台有更多有用的错误消息:
WebSocket connection to 'ws://127.0.0.1:8080/live/ws_zones' failed: Error during WebSocket handshake: Invalid status line
好的,我们有一个握手问题。
如果你打开 Wireshark(或其他嗅探器),你可以看到我们的 Login 0
确实出现在 ws4py
以握手响应(或者可能存在竞争条件)的回复之前。
我能理解你的困惑,因为在几个地方 ws4py
文档要么暗示要么直接引导你错误的方式。让我们看看:
alludes — 您不能从普通处理程序发送。
@cherrypy.expose
def ws(self):
# you can access the class instance through
handler = cherrypy.request.ws_handler
guides incorrectly — 你不能从 opened
挂钩发送。
def opened(self):
"""
Called by the server when the upgrade handshake
has succeeeded.
"""
pass
所以我认为这是过时的文档或错误。
解决方案
现在我建议您在客户端发起通信。如果你有一些预登录 "chat",你可以在网络套接字之上做一个小协议(无论如何你最终都会这样做)。像这样:
#!/usr/bin/env python3
import json
import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import WebSocket
class LoginLiveWebSocketHandler(WebSocket):
wsset = set()
'''Class level attr, do not rebind'''
def opened(self):
'''You can not send yet, because handshake has not been completed.
Yes, a documentation is not always correct ;-)
'''
cherrypy.log('Opened!')
self.wsset.add(self)
def closed(self, code, reason = ''):
cherrypy.log('Closed!')
self.wsset.remove(self)
def received_message(self, message):
cherrypy.log('Received Message!')
message = json.loads(message.data.decode())
if message['cmd'] == 'init':
self.send('Login 0')
else:
self.send(message['payload'] + ' pong')
class LiveService(object):
@cherrypy.expose
def index(self):
return '''<!DOCTYPE html>
<html>
<body>
<div id='log'></div>
<script type='application/javascript'>
var ws = new WebSocket('ws://127.0.0.1:8080/live/ws_zones');
ws.onopen = function(event)
{
ws.send(JSON.stringify({'cmd': 'init'}));
};
ws.onmessage = function(event)
{
document.getElementById('log').innerHTML += event.data + '<br/>';
};
var handle = setInterval(function()
{
if(ws.readyState == WebSocket.CLOSING || ws.readyState == WebSocket.CLOSED)
{
clearInterval(handle);
}
else
{
ws.send(JSON.stringify({'cmd': 'chat', 'payload': 'ping'}));
}
}, 1000);
</script>
</body>
</html>
'''
@cherrypy.expose
def ws_zones(self):
'''You can not send yet, because handshake has not been completed'''
cherrypy.log('Handler created: %r' % cherrypy.request.ws_handler)
if __name__ == '__main__':
cherrypy.config.update({
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
})
cherrypy.tools.websocket = WebSocketTool()
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tree.mount(LiveService(), '/live', {
'/ws_zones' : {
'tools.websocket.on' : True,
'tools.websocket.handler_cls' : LoginLiveWebSocketHandler
}
})
cherrypy.engine.signals.subscribe()
cherrypy.engine.start()
cherrypy.engine.block()
有点傻...
@saaj 是对的,但真正的问题是我试图用 m、m.data 等调用函数 log(需要 str)。使用 repr() 或删除它来执行此操作,它有效!
谢谢!