2015-07-21 2 views
1

У меня возникают проблемы при создании сервера/клиента WebSocket.ws4py - send/received_message не работает

Это мой WebSocket Clas:

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)") 

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) 

Итак, монтажные и пуско-наладочные работы, все работает в течение нескольких месяцев, но новый LiveService с ws не работает. В журнале, im получение [21/Jul/2015:16:55:28] ENGINE Starting WebSocket processing и Opened Сообщения, но я никогда не получаю и не могу отправлять Сообщения. Когда я изменяю LiveService.LoginLiveServiceWebSocketHandler к EchoWebSocket он получает сообщения и отправляет их, но на обработчик ws_zones

cherrypy.request.ws_handler.send (б "Логин 0", False)

не работает. с b или нет.

+0

Показать свой 'LiveService.LiveService'. – saaj

+0

Добавлен LiveService. – decontamin4t0R

ответ

0

был немного глупо ...

@saaj был прав, но реальная проблема в том, что я пытался вызвать функцию журнала (который требует НТР) с м, m.data и т. д. Выполняя это с помощью функции repr() или удаления, это сработало!

Спасибо!

1

Анализ

Первое, что нужно сказать, что вы должны обратить внимание на средства отладки, которые у вас распоряжении. Например, когда вы пытаетесь вам приложение в Firefox, Firebug (или веб-консоли) говорит вам:

Firefox не может установить соединение с сервером на веб-службой: //127.0.0.1: 8080/Live/ws_zones ,

Хром консоль имеет более полезное сообщение об ошибке:

подключение WebSocket к 'WS: //127.0.0.1: 8080/живой/ws_zones' не удалось: Ошибка при WebSocket рукопожатия: Invalid строки состояния

Хорошо, у нас проблема с рукопожатием.

Если вы открываете 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 

Поэтому я считаю, что это устаревшая документация или ошибка.

Решение

Сейчас я предлагаю вам начать ваше общение на стороне клиента. Если у вас есть предварительный «чат», вы можете сделать небольшой протокол поверх веб-сокетов (в любом случае вы все равно это сделаете). Что-то вроде этого:

#!/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() 
+0

Спасибо! Попытка сделать это сейчас! – decontamin4t0R