uWSGI:通过websockets

时间:2015-05-23 17:04:02

标签: python python-3.x websocket uwsgi

我是uWSGI的新手,我正在开发一个需要大量网络套接字通信的Web应用程序。我决定通过创建一个简单的聊天应用程序来练习。

来自uWSGI docs

def application(env, start_response):
    # complete the handshake
    uwsgi.websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env.get('HTTP_ORIGIN', ''))
    while True:
        msg = uwsgi.websocket_recv()
        uwsgi.websocket_send(msg)

我不想使用这种方法,因为

  1. 只有在他向您发送信息后,您才能向客户发送信息;
  2. 您无权访问其他websocket连接,因此基本上您只与1个客户端通信。
  3. 然而,同一页面有example如何实现聊天。它会很棒,但他们在他们的例子中使用Redis:

        r = redis.StrictRedis(host='localhost', port=6379, db=0)
        channel = r.pubsub()
        channel.subscribe('foobar')
    
        websocket_fd = uwsgi.connection_fd()
        redis_fd = channel.connection._sock.fileno()
    
        while True:
            uwsgi.wait_fd_read(websocket_fd, 3)
            uwsgi.wait_fd_read(redis_fd)
            uwsgi.suspend()
    

    从我看到的,Redis在这里用作外部服务器,允许不同的uWSGI请求处理程序使用相同的数据。

    这真的需要那么困难吗?

    使用Node.js查看聊天解决方案(来自javascript.ru的示例):

    var WebSocketServer = new require('ws');
    
    // connected clients
    var clients = {};
    
    // WebSocket-server serves 8081 port
    var webSocketServer = new WebSocketServer.Server({
      port: 8081
    });
    webSocketServer.on('connection', function(ws) {
    
      var id = Math.random();
      clients[id] = ws;
      console.log("new connection " + id);
    
      ws.on('message', function(message) {
        console.log("recieved a new message: " + message);
    
        for (var key in clients) {
          clients[key].send(message);
        }
      });
    
      ws.on('close', function() {
        console.log("connection closed " + id);
        delete clients[id];
      });
    
    });
    

    我真正喜欢的是

    1. 基于事件的方法允许我随时向客户发送数据
    2. 所有客户端都存储在简单的clients字典中。我可以轻松访问它,无需使用某些外部服务器在客户端之间交换数据。
    3. 为了解决uWSGI中的第一个问题(基于非阻塞事件的方法),我编写了这段代码片段:

      import uwsgi
      from threading import Thread
      
      
      class WebSocket(Thread):
          def __init__(self, env):
              super().__init__()
              self.listeners = []
              self._env = env
      
          def run(self):
              self._working = True
              uwsgi.websocket_handshake(
                  self._env['HTTP_SEC_WEBSOCKET_KEY'], self._env.get('HTTP_ORIGIN', ''))
      
              while self._working:
                  msg = uwsgi.websocket_recv()
                  for listener in self.listeners:
                      listener(msg)
      
          def send(self, msg):
              uwsgi.websocket_send(msg)
      
          def close(self):
              self._working = False
      

      所以我的第一个问题是这是否有效。

      第二个问题是我如何在请求处理程序之间交换数据。我觉得我完全误解了uWSGI的设计。 我使用uwsgi --http :80 --wsgi-file=main.py --master --static-map /st=web-static来测试我的应用程序。理想情况下,我只需在main.py中定义一个对象并使用它,但我认为这个main.py将在不同的worker / threads / process中多次初始化。

      我已经在数据交换上看到了类似的问题:Communication between workers in uwsgi

      答案是

        

      注意,只有当你有一个工人/过程时它才会起作用。另一种常见方法是使用uWSGI缓存框架(名称具有误导性,实际上是共享字典)。它允许您在工作线程和线程之间共享数据。

      我将这个uWSGI缓存框架视为某种独立的外部数据存储(参见上面的Redis示例)。但是在我看到Node.js上的整洁实现后,我不想使用任何缓存框架,只是在所有请求处理程序中共享相同的python对象。

1 个答案:

答案 0 :(得分:2)

首先,您应该投资学习同步与异步编程范例。节点方法似乎更容易,但这只是因为您只需要一个进程来管理。如果你需要扩展(到多台机器或简单的多个进程),你就会回到“python问题”。有一个外部通道(如redis)是一种常见的模式,你应该使用它,因为它可以让你轻松扩展。

关于python,uWSGI和websockets我强烈怀疑你看看gevent。 uWSGI websockets系统支持它,并且有很多例子。您将能够增加并发性,而无需依赖基于回调的编程。

最终(但只有你喜欢回调)你才能看看龙卷风。