【问题标题】:Hiredis waiting for messageHiredis 等待消息
【发布时间】:2013-04-25 11:35:32
【问题描述】:

我正在使用hiredis C 库连接到redis 服务器。订阅新消息后,我无法弄清楚如何等待新消息。

我的代码如下:

signal(SIGPIPE, SIG_IGN );
  struct event_base *base = event_base_new();

  redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
  if (c->err) {
    /* Let *c leak for now... */
    printf("Error: %s\n", c->errstr);
    return 1;
  }

  redisLibeventAttach(c, base);
  redisAsyncSetConnectCallback(c, connectCallback);
  redisAsyncSetDisconnectCallback(c, disconnectCallback);
  redisAsyncCommand(c, NULL, NULL, "SET key %b", argv[argc - 1],
                    strlen(argv[argc - 1]));
  redisAsyncCommand(c, getCallback, (char*) "end-1", "GET key");
  redisAsyncCommand(c, getCallback, (char*) "end-1", "SUBSCRIBE foo");

现在如何告诉hiredis等待频道上的消息?

【问题讨论】:

    标签: redis hiredis


    【解决方案1】:

    你不必告诉hiredis你需要在频道上等待:事件循环只会等待之前注册的Redis连接。

    这是一个完整的例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include "hiredis.h"
    #include "async.h"
    #include "adapters/libevent.h"
    
    void subCallback(redisAsyncContext *c, void *r, void *priv) {
        redisReply *reply = r;
        if (reply == NULL) return;
        if ( reply->type == REDIS_REPLY_ARRAY && reply->elements == 3 ) {
            if ( strcmp( reply->element[0]->str, "subscribe" ) != 0 ) {
                printf( "Received[%s] channel %s: %s\n",
                        (char*)priv,
                        reply->element[1]->str,
                        reply->element[2]->str );
            }
        }
    }
    
    void connectCallback(const redisAsyncContext *c, int status) {
        if (status != REDIS_OK) {
            printf("Error: %s\n", c->errstr);
            return;
        }
        printf("Connected...\n");
    }
    
    void disconnectCallback(const redisAsyncContext *c, int status) {
        if (status != REDIS_OK) {
            printf("Error: %s\n", c->errstr);
            return;
        }
        printf("Disconnected...\n");
    }
    
    int main (int argc, char **argv) {
        signal(SIGPIPE, SIG_IGN);
        struct event_base *base = event_base_new();
    
        redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
        if (c->err) {
            /* Let *c leak for now... */
            printf("Error: %s\n", c->errstr);
            return 1;
        }
    
        redisLibeventAttach(c,base);
        redisAsyncSetConnectCallback(c,connectCallback);
        redisAsyncSetDisconnectCallback(c,disconnectCallback);
        redisAsyncCommand(c, subCallback, (char*) "sub", "SUBSCRIBE foo");
    
        event_base_dispatch(base);
        return 0;
    }
    

    您可以通过使用以下命令发布内容来测试它:

    redis-cli publish foo something
    

    event_base_dispatch 函数是真正启动事件循环的函数,并使其等待 Redis 订阅。

    【讨论】:

    • 这对我不起作用。我发布时没有收到任何消息
    【解决方案2】:

    基于LibUV的解决方案

    Redis 版本:5.0.5

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include "hiredis.h"
    #include "async.h"
    #include <time.h>
    #include <uv.h>
    #include "adapters/libevent.h"
    #include "adapters/libuv.h"
    
    void subCallback(redisAsyncContext *c, void *r, void *priv) {
        redisReply *reply = r;
        time_t seconds;
        seconds = time(NULL);
        if (reply == NULL) return;
        if (reply->type == REDIS_REPLY_ARRAY && reply->elements == 3) {
            if (strcmp(reply->element[0]->str, "subscribe") != 0) {
                printf("[%d] Received[%s] channel %s: %s\n",
                       seconds,
                        (char *) priv,
                       reply->element[1]->str,
                       reply->element[2]->str);
            }
        }
    }
    
    void connectCallback(const redisAsyncContext *c, int status) {
        if (status != REDIS_OK) {
            printf("Error: %s\n", c->errstr);
            return;
        }
        printf("Connected...\n");
    }
    
    void disconnectCallback(const redisAsyncContext *c, int status) {
        if (status != REDIS_OK) {
            printf("Error: %s\n", c->errstr);
            return;
        }
        printf("Disconnected...\n");
    }
    
    int main(int argc, char **argv) {
        signal(SIGPIPE, SIG_IGN);
        uv_loop_t *loop = malloc(sizeof(uv_loop_t));
        uv_loop_init(loop);
    
        redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);
        if (c->err) {
            /* Let *c leak for now... */
            printf("Error: %s\n", c->errstr);
            return 1;
        }
    
        redisLibuvAttach(c, loop);
        redisAsyncSetConnectCallback(c, connectCallback);
        redisAsyncSetDisconnectCallback(c, disconnectCallback);
        redisAsyncCommand(c, subCallback, (char *) "sub", "SUBSCRIBE test-channel");
    
        uv_run(loop, UV_RUN_DEFAULT);
        uv_loop_close(loop);
        free(loop);
        return 0;
    }
    

    【讨论】:

    • 这正是行不通的。将 libevent 示例转换为 libuv 示例不是问题。上面的代码没有收到从redis-cli 发布到test-channel 的消息。
    • 您可以提供任何其他详细信息吗?
    • 服务器在本地主机上(并且在不同主机上测试时使用 --protect-mode no)。两个独立的redis-cli。我可以毫无问题地在这些 cli 之间发布和订阅。当我如上所述启动应用程序时,服务器(以--loglevel debug 开始)显示连接。当我在其中一个 redis-cli 上发布时,另一个 cli 得到它,但上面的应用程序没有。我到处都设置了断点,uv 循环运行得很好。只是没有消息通过管道。
    • 6.0.10。使用 redis 树中包含的hiredis。
    • 即使使用最新的 Redis 版本,它在我的笔记本电脑上也能正常工作。我在 Mac Os 上运行,您可以提供任何其他详细信息来重现此问题吗?
    猜你喜欢
    • 2020-07-02
    • 1970-01-01
    • 1970-01-01
    • 2014-09-15
    • 2011-06-09
    • 2021-04-23
    • 2012-09-26
    • 2013-12-07
    • 2015-04-15
    相关资源
    最近更新 更多