uWSGI:通过 websockets 与多个客户端一起工作
uWSGI: working with multiple clients through websockets
我是 uWSGI 的新手,我正在开发一个需要大量网络套接字通信的网络应用程序。我决定通过创建一个简单的聊天应用程序来练习。
来自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)
我不想使用这种方法,因为
- 您的客户只有在他给您发了东西后才能给您发消息;
- 您无权访问其他 websocket 连接,所以基本上您只与 1 个客户端通信。
但是,同一页面上有 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];
});
});
我真正喜欢这里的是
- 基于事件的方法允许我随时向客户端发送数据
- 所有客户端都存储在一个简单的
clients
字典中。我可以很容易地访问它,不需要使用一些外部服务器在客户端之间交换数据。
为了解决 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
将在不同的 workers/threads/process.
中多次初始化
我已经看到一个关于数据交换的类似问题:Communication between workers in uwsgi
答案是
Pay attention, it will works only if you have a single worker/process. Another common approach is using the uWSGI caching framework (the name is misleading, infact is a shared dictionary). It will allows you to share data between workers and threads.
我将这个 uWSGI 缓存框架视为某种独立的外部数据存储(参见上面的 Redis 示例)。但是在我看到 Node.js 上的简洁实现后,我不想不使用任何缓存框架,而只是在所有请求处理程序之间共享相同的 python 对象。
首先,您应该投资学习同步与异步编程范例。节点方法似乎更容易,但这只是因为您需要管理一个进程。如果你需要扩展(到多台机器或简单的多进程),你又回到了 "python problems"。拥有外部通道(如 Redis)是一种常见模式,您应该使用它,因为它可以让您轻松扩展。
关于python,uWSGI和websockets我强烈建议你看看gevent。 uWSGI websockets 系统支持它并且那里有很多例子。您将能够提高并发性,而无需依赖基于回调的编程。
最终(但前提是您喜欢回调)您可以看看 tornado。
我是 uWSGI 的新手,我正在开发一个需要大量网络套接字通信的网络应用程序。我决定通过创建一个简单的聊天应用程序来练习。
来自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)
我不想使用这种方法,因为
- 您的客户只有在他给您发了东西后才能给您发消息;
- 您无权访问其他 websocket 连接,所以基本上您只与 1 个客户端通信。
但是,同一页面上有 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];
});
});
我真正喜欢这里的是
- 基于事件的方法允许我随时向客户端发送数据
- 所有客户端都存储在一个简单的
clients
字典中。我可以很容易地访问它,不需要使用一些外部服务器在客户端之间交换数据。
为了解决 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
将在不同的 workers/threads/process.
我已经看到一个关于数据交换的类似问题:Communication between workers in uwsgi
答案是
Pay attention, it will works only if you have a single worker/process. Another common approach is using the uWSGI caching framework (the name is misleading, infact is a shared dictionary). It will allows you to share data between workers and threads.
我将这个 uWSGI 缓存框架视为某种独立的外部数据存储(参见上面的 Redis 示例)。但是在我看到 Node.js 上的简洁实现后,我不想不使用任何缓存框架,而只是在所有请求处理程序之间共享相同的 python 对象。
首先,您应该投资学习同步与异步编程范例。节点方法似乎更容易,但这只是因为您需要管理一个进程。如果你需要扩展(到多台机器或简单的多进程),你又回到了 "python problems"。拥有外部通道(如 Redis)是一种常见模式,您应该使用它,因为它可以让您轻松扩展。
关于python,uWSGI和websockets我强烈建议你看看gevent。 uWSGI websockets 系统支持它并且那里有很多例子。您将能够提高并发性,而无需依赖基于回调的编程。
最终(但前提是您喜欢回调)您可以看看 tornado。