等待gevent套接字和Redis阻塞blpop

0 投票
1 回答
1329 浏览
提问于 2025-04-17 16:36

我正在使用 gevent 的 StreamServer 来处理来自客户端的连接。

当客户端连接上后,它会向服务器发送一些消息,服务器会处理这些消息。这一切都运行得很好。但有时候,服务器也需要向特定的客户端发送消息。

我打算用 Redis 来实现这个功能。我创建了一个队列,用特定的客户端 ID 作为键。当客户端发送消息后,我会检查这个队列,如果有消息,我就把它发回给客户端。

这种方法的缺点是,服务器只能在客户端发送消息之后才能发送消息。

有没有办法让我同时等待接收数据和 Redis 的 blpop,这样我就可以在消息准备好后立即把它发回给客户端,而不是等到客户端发送下一条数据?

import gevent
from gevent import socket
from gevent.server import StreamServer
import redis 

r = redis.Redis('localhost')

def handle_echo(sock, address):
    fp = sock.makefile()
    while True:
        line = fp.readline()
        if line:
            client_id = line.split(",")[0]
            if r.llen('%s:servercmds' % client_id) > 0:
                tosend = r.lrange('%s:servercmds' % imei, 0, 0)[0]
                try:        
                    fp.write(tosend)
                    fp.flush()
                    r.lpop('%s:servercmds' % imei)
                except:
                    print('cannot send data to client')
            else:
                break
        sock.shutdown(socket.SHUT_WR)
        sock.close()

server = StreamServer(('', 8045), handle_echo, spawn=10000)
server.serve_forever()

1 个回答

1

你需要让客户端保持连接,这样你才能把消息发回去,或者客户端自己也可以在监听消息。

补充说明:这段代码是我随便想出来的。在我看来,把读取和写入分开处理是很常见的做法。不过,这并不是你可以使用的唯一方式。

import gevent
from gevent import socket
from gevent.server import StreamServer
import redis 

r = redis.Redis('localhost')

def handle_echo(sock, address):
    def read_loop(sock):
        while True:
            try:
                socket.wait_read(sock.fileno())
            except socket.error:
                break
            # read from socket

    def write_loop(sock):
        while True:
            try:
                socket.wait_write(sock.fileno())
            except socket.error:
                break
            # write to socket

    jobs = [gevent.spawn(func, sock) for func in (read_loop, write_loop)]
    gevent.joinall(jobs)

server = StreamServer(('', 8045), handle_echo)
server.serve_forever()

撰写回答