ws4py - send/received_message not working



我在制作WebSocket服务器/客户端时遇到了问题。

这是我的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(/liveu002flive$/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)")

LiveService:

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 processingOpened消息,但我从来没有收到或能够发送消息。当我更改livesservice时。LoginLiveServiceWebSocketHandler到echowbsocket他获取消息并发送它们,但是在ws_zones处理程序

cherrypy.request.ws_handler。send(b"Login 0", False)

不能工作。

分析

首先要说的是,您应该注意您可以使用的调试工具。例如,当你在Firefox中尝试应用程序时,Firebug(或Web Console)会告诉你:

Firefox无法连接到服务器:ws://127.0.0.1:8080/live/ws_zones.

Chromium控制台有更多有用的错误信息:

WebSocket连接到'ws://127.0.0.1:8080/live/ws_zones'失败:WebSocket握手时错误:Invalid status line

好吧,我们有一个握手的问题。

如果你打开Wireshark(或另一个嗅探器),你可以看到我们的Login 0确实出现在ws4py回复握手响应之前(或者可能有竞争条件)。

我可以理解你的困惑,因为在几个地方ws4py文档要么暗示或直接引导你错误的方式。让我们看看:

暗示 -您不能从正常处理程序发送。

@cherrypy.expose
def ws(self):
    # you can access the class instance through
    handler = cherrypy.request.ws_handler

引导不正确 -你不能从opened钩子发送。

def opened(self):
    """
    Called by the server when the upgrade handshake
    has succeeeded.
    """
    pass

所以我认为这要么是一个过时的文档,要么是一个bug。

<标题> 解决方案

现在我建议你从客户端开始沟通。如果你有一些登录前的"聊天",你可以在web套接字上做一个小协议(你最终会这样做)。像这样:

#!/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是对的,但真正的问题是,我试图调用函数log(这需要str)与m, m.data等。通过repr()或删除它来执行此操作,它工作了!

谢谢!

相关内容

  • 没有找到相关文章

最新更新