ws4py под cherrypy под WSGI: исключение AttributeError: объект «mod_wsgi.Input» не имеет атрибута «rfile»

Я пытаюсь реализовать веб-сокеты на сервере openshift.com (который должен их поддерживать).

openshift.com предоставляет мне WSGI, поэтому я встраиваю в него свой cherrypy, чтобы мой wsgi.pyscript определял объект application. Кроме того, cherrypy имеет инструмент веб-сокета, как определено ws4py.

Это минимальное приложение cherrypy, которое работает под WSGI в OpenShift и которое должно также использовать веб-сокеты!

import cherrypy
from ws4py.server.cherrypyserver import WebSocketPlugin, WebSocketTool
from ws4py.websocket import EchoWebSocket
import atexit
import logging

# see http://tools.cherrypy.org/wiki/ModWSGI
cherrypy.config.update({'environment': 'embedded'}) 
if cherrypy.__version__.startswith('3.0') and cherrypy.engine.state == 0:
    cherrypy.engine.start(blocking=False)
    atexit.register(cherrypy.engine.stop)

class Root(object):
    def index(self): return 'I work!'
    def ws(self): print('THIS IS NEVER PRINTED :(')
    index.exposed=True
    ws.exposed=True

# registering the websocket
conf={'/ws':{'tools.websocket.on': True,'tools.websocket.handler_cls': EchoWebSocket}}
WebSocketPlugin(cherrypy.engine).subscribe()
cherrypy.tools.websocket = WebSocketTool()  

#show stacktraces in console (for some reason this is not default in cherrypy+WSGI)
logger = logging.getLogger()
logger.setLevel(logging.INFO)
stream = logging.StreamHandler()
stream.setLevel(logging.INFO)
logger.addHandler(stream)

application = cherrypy.Application(Root(), script_name='', config=conf)

Все работает прекрасно, за исключением случаев, когда я создаю веб-сокет (подключаясь к ws://myserver:8000/ws), я получаю трассировку стека:

 cherrypy/_cplogging.py, 214, HTTP Traceback (most recent call last):
   File "cherrypy/_cprequest.py", line 661, in respond
     self.hooks.run('before_request_body')
   File "cherrypy/_cprequest.py", line 114, in run
     raise exc
   File "cherrypy/_cprequest.py", line 104, in run
     hook()
   File "cherrypy/_cprequest.py", line 63, in __call__
     return self.callback(**self.kwargs)
   File "ws4py/server/cherrypyserver.py", line 200, in upgrade
     ws_conn = get_connection(request.rfile.rfile)
AttributeError: 'mod_wsgi.Input' object has no attribute 'rfile'

(Я вручную удалил абсолютный путь из имен файлов) PS: Я использую python3.3, cherrypy==3.5.0, ws4py==0.3.4.

Мне непонятно:

  • если это отсутствие совместимости между cherrypy и ws4py в среде WSGI.
  • если это проблема ws4py в среде WSGI
  • если это потому, что веб-сокеты Openshift имеют другой порт, чем http

PPS: это полноценный проект OpenShift, который вы можете запустить и попробовать сами: https://github.com/spocchio/wsgi-cherrypy-ws4py


person Antonio Ragagnin    schedule 15.09.2014    source источник


Ответы (1)


Я вообще не думаю, что это возможно. WSGI — это синхронный протокол (1, 2), протокол WebSocket является асинхронным. Wiki утверждает, что для интерфейса приложения Python OpenShift использует WSGI (3). Увы.

Однако недавно я поиграл с ws4py в сценарии pub/sub, и он отлично работает поверх стандартного развертывания HTTP-сервера CherryPy. Так что это не должно быть проблемой на обычном виртуальном сервере без ограничений интерфейса приложений.

person saaj    schedule 15.09.2014
comment
Я знаю, на Heroku это работает отлично. К сожалению, у них есть 55-секундный тайм-аут на веб-сокетах, поэтому клиент должен поддерживать соединение как минимум раз в минуту (не лучший вариант для мобильного приложения, работающего в фоновом режиме). - person Antonio Ragagnin; 15.09.2014
comment
Хотя спецификация WSGI технически запрещает это, проблема больше связана с используемым сервером WSGI. Код WebSocket полагается на использование на сервере WSGI, реализованном как чистый сервер Python WSGI, который имеет дело непосредственно с самим клиентским сокетом. Затем он обходит спецификацию WSGI и сервер WSGI и достигает фактического соединения сокета для клиента и связывается напрямую через него. Другими словами, он использует злой хак. Этот хак не будет работать на mod_wsgi, так как он не раскрывает исходное соединение сокета. - person Graham Dumpleton; 16.09.2014
comment
Чтобы было понятнее, я бы добавил, что в случае Python Openshift использует веб-сервер Apache, поэтому mod_wsgi для WSGI . То, что Грэм называет злым взломом, задокументировано в модуль ws4py CherryPy. - person saaj; 16.09.2014
comment
Мне действительно пришлось выполнить такой хак, которым я не очень гордился. К сожалению, спецификация WSGI была написана задолго до WebSocket и не учитывала этот вариант использования. Надеюсь, когда-нибудь в него будут внесены поправки. - person Sylvain Hellegouarch; 28.01.2015