hiredis接口分析3:同步调用的超时设定

hiredis接口分析1:同步调用中我们介绍了同步调用的执行流程,当时给的例子中,发送数据的socket默认是阻塞的,也就是如果发送或接收未完成会一直等待,下面我们将进一步介绍非阻塞模式的设定,我们知道socket的超时的基本设定是通过setsockopt函数实现的,hiredis同样是通过封装该函数来实现的,直接给出示例:

#include <stdio.h>
#include <string.h>
#include "hiredis.h"
int main()
{
unsigned isunix = 0;
redisContext *c;
struct timeval timeout = { 1, 500000 }; // 1.5 seconds
if (isunix) {
    c = redisConnectUnixWithTimeout("192.168.0.18", timeout);
} else {
    c = redisConnectWithTimeout("192.168.0.18", 9688, timeout);
}

redisReply *reply = (redisReply *)redisCommand(c, "AUTH %s", "123456");
if (reply->type == REDIS_REPLY_ERROR) {
printf("Redis log in fail!\n");
}
else
{
printf("Redis log in success!\n");
}
freeReplyObject(reply);
char *value="It's a test";
redisReply *reply1 = redisCommand(c, "set key %s", value);
freeReplyObject(reply1);
redisReply *reply2 = redisCommand(c, "get key");
printf("key:1 value:%s\n", reply2->str);
freeReplyObject(reply2);
redisFree(c);
return 0;
}

代码和hiredis接口分析1:同步调用中的代码基本一样,主要区别是redisConnectWithTimeout替代了redisConnect,我们看下redisConnectWithTimeout的源代码:

redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) {
    redisOptions options = {0};
    REDIS_OPTIONS_SET_TCP(&options, ip, port);
    options.timeout = &tv;
    return redisConnectWithOptions(&options);
}

在设定了ip、端口号和超时以后实际调用了函数redisConnectWithOptions:

redisContext *redisConnectWithOptions(const redisOptions *options) {
    redisContext *c = redisContextInit(options);
    if (c == NULL) {
        return NULL;
    }
    if (!(options->options & REDIS_OPT_NONBLOCK)) {
        c->flags |= REDIS_BLOCK;
    }
    if (options->options & REDIS_OPT_REUSEADDR) {
        c->flags |= REDIS_REUSEADDR;
    }
    if (options->options & REDIS_OPT_NOAUTOFREE) {
      c->flags |= REDIS_NO_AUTO_FREE;
    }

    if (options->type == REDIS_CONN_TCP) {
        redisContextConnectBindTcp(c, options->endpoint.tcp.ip,
                                   options->endpoint.tcp.port, options->timeout,
                                   options->endpoint.tcp.source_addr);
    } else if (options->type == REDIS_CONN_UNIX) {
        redisContextConnectUnix(c, options->endpoint.unix_socket,
                                options->timeout);
    } else if (options->type == REDIS_CONN_USERFD) {
        c->fd = options->endpoint.fd;
        c->flags |= REDIS_CONNECTED;
    } else {
        // Unknown type - FIXME - FREE
        return NULL;
    }
    if (options->timeout != NULL && (c->flags & REDIS_BLOCK) && c->fd != REDIS_INVALID_FD) {
        redisContextSetTimeout(c, *options->timeout);
    }
    return c;
}

可以看到首先执行通过tcp连接服务端,连接成功并返回后在设定超时,超时通过函数redisContextSetTimeout实现:

int redisContextSetTimeout(redisContext *c, const struct timeval tv) {
    const void *to_ptr = &tv;
    size_t to_sz = sizeof(tv);
#ifdef _WIN32
    DWORD timeout_msec = tv.tv_sec * 1000 + tv.tv_usec / 1000;
    to_ptr = &timeout_msec;
    to_sz = sizeof(timeout_msec);
#endif
    if (setsockopt(c->fd,SOL_SOCKET,SO_RCVTIMEO,to_ptr,to_sz) == -1) {
        __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_RCVTIMEO)");
        return REDIS_ERR;
    }
    if (setsockopt(c->fd,SOL_SOCKET,SO_SNDTIMEO,to_ptr,to_sz) == -1) {
        __redisSetErrorFromErrno(c,REDIS_ERR_IO,"setsockopt(SO_SNDTIMEO)");
        return REDIS_ERR;
    }
    return REDIS_OK;
}

分别通过setsockopt设定发送和接收的超时。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值