深入浅出hiredis -- C++操作redis
【摘要】
本文暂不设目录,因为真不知道怎么设。
由于hiredis是个动态库,所以刚开始也不知道该从哪里下手,好在开发人员提供了一些测试案例,所以我就跟着测试案例的脚步来进行分析学习吧。
如果要快速上手,可以使用这一篇教程:学以致用 - C++操作redis 便无需在本篇耗费过多时间了,收藏一下,以后慢慢看
有需要完整示例,可以私信我。
#include <stdio...
本文暂不设目录,因为真不知道怎么设。
由于hiredis是个动态库,所以刚开始也不知道该从哪里下手,好在开发人员提供了一些测试案例,所以我就跟着测试案例的脚步来进行分析学习吧。
如果要快速上手,可以使用这一篇教程:学以致用 - C++操作redis
便无需在本篇耗费过多时间了,收藏一下,以后慢慢看
有需要完整示例,可以私信我。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <hiredis.h>
这是头文件,#include<hiredis/hiredis.h>
int main(int argc, char **argv) { unsigned int j, isunix = 0; redisContext *c; //注1: redisReply *reply; //注2: const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1"; if (argc > 2) { if (*argv[2] == 'u' || *argv[2] == 'U') { isunix = 1; /* in this case, host is the path to the unix socket */ printf("Will connect to unix socket @%s\n", hostname); } } int port = (argc > 2) ? atoi(argv[2]) : 6379;
插入:
注1:redisContext
/* Context for a connection to Redis */
typedef struct redisContext { const redisContextFuncs *funcs; /* Function table */ /* typedef struct redisContextFuncs { void (*free_privdata)(void *); void (*async_read)(struct redisAsyncContext *); void (*async_write)(struct redisAsyncContext *); int (*read)(struct redisContext *, char *, size_t); int (*write)(struct redisContext *); } redisContextFuncs;
*/ int err; /* Error flags, 0 when there is no error */ char errstr[128]; /* String representation of error when applicable */ redisFD fd; /* #ifndef _WIN32 typedef int redisFD; #define REDIS_INVALID_FD -1 #else #ifdef _WIN64 typedef unsigned long long redisFD; //SOCKET = 64-bit UINT_PTR #else typedef unsigned long redisFD; // SOCKET = 32-bit UINT_PTR #endif #define REDIS_INVALID_FD ((redisFD)(~0)) // INVALID_SOCKET #endif */ int flags; char *obuf; /* Write buffer */ redisReader *reader; /* Protocol reader */ /* typedef struct redisReader { int err; /* Error flags, 0 when there is no error char errstr[128]; /* String representation of error when applicable char *buf; /* Read buffer size_t pos; /* Buffer cursor size_t len; /* Buffer length size_t maxbuf; /* Max length of unused buffer redisReadTask rstack[9]; /* typedef struct redisReadTask { int type; int elements; /* number of elements in multibulk container int idx; /* index in parent (array) object void *obj; /* holds user-generated value for a read task struct redisReadTask *parent; /* parent task void *privdata; /* user-settable arbitrary field } redisReadTask; int ridx; /* Index of current read task void *reply; /* Temporary reply pointer redisReplyObjectFunctions *fn; void *privdata; } redisReader; */ enum redisConnectionType connection_type;
/* enum redisConnectionType { REDIS_CONN_TCP, REDIS_CONN_UNIX, REDIS_CONN_USERFD };
*/ struct timeval *timeout; struct { char *host; char *source_addr; int port; } tcp; struct { char *path; } unix_sock; /* For non-blocking connect */ struct sockadr *saddr; size_t addrlen; /* Additional private data for hiredis addons such as SSL */ void *privdata;
} redisContext;
注2:redisReply
/* This is the reply object returned by redisCommand() */
typedef struct redisReply { int type; /* REDIS_REPLY_* */ long long integer; /* The integer when type is REDIS_REPLY_INTEGER */ double dval; /* The double when type is REDIS_REPLY_DOUBLE */ size_t len; /* Length of string */ char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING and REDIS_REPLY_DOUBLE (in additionl to dval). */ char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null terminated 3 character content type, such as "txt". */ size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */ struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;
好,我们继续看示例代码。
struct timeval timeout = { 1, 500000 }; // 1.5 seconds if (isunix) { c = redisConnectUnixWithTimeout(hostname, timeout); //注3: } else { c = redisConnectWithTimeout(hostname, port, timeout); } if (c == NULL || c->err) { if (c) { printf("Connection error: %s\n", c->errstr); redisFree(c); //注4: } else { printf("Connection error: can't allocate redis context\n"); } exit(1); }
插入:
注3:
redisContext *redisConnectWithTimeout(const char *ip, int port, const struct timeval tv) { redisOptions options = {0};
/*
typedef struct { /* * the type of connection to use. This also indicates which * `endpoint` member field to use int type; /* bit field of REDIS_OPT_xxx int options; /* timeout value. if NULL, no timeout is used const struct timeval *timeout; union { /** use this field for tcp/ip connections struct { const char *source_addr; const char *ip; int port; } tcp; /** use this field for unix domain sockets const char *unix_socket; /** * use this field to have hiredis operate an already-open * file descriptor redisFD fd; } endpoint;
} redisOptions;
*/ REDIS_OPTIONS_SET_TCP(&options, ip, port); /* #define REDIS_OPTIONS_SET_TCP(opts, ip_, port_) \ (opts)->type = REDIS_CONN_TCP; \ (opts)->endpoint.tcp.ip = ip_; \ (opts)->endpoint.tcp.port = port_; */ options.timeout = &tv; return redisConnectWithOptions(&options); //注3.5
}
//该函数用来连接redis数据库, 两个参数分别是redis数据库的ip和端口,端口号一般为6379。
注3.5:redisConnectWithOptions
redisContext *redisConnectWithOptions(const redisOptions *options) { redisContext *c = redisContextInit(options); //注3.5.5 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;
}
注3.5.5:redisContextInit
static redisContext *redisContextInit(const redisOptions *options) { redisContext *c; c = calloc(1, sizeof(*c)); if (c == NULL) return NULL; c->funcs = &redisContextDefaultFuncs; c->obuf = sdsempty(); c->reader = redisReaderCreate(); c->fd = REDIS_INVALID_FD; if (c->obuf == NULL || c->reader == NULL) { redisFree(c); return NULL; } (void)options; /* options are used in other functions */ return c;
}
注4:redisFree
void redisFree(redisContext *c) { if (c == NULL) return; redisNetClose(c); sdsfree(c->obuf); redisReaderFree(c->reader); free(c->tcp.host); free(c->tcp.source_addr); free(c->unix_sock.path); free(c->timeout); free(c->saddr); if (c->funcs->free_privdata) { c->funcs->free_privdata(c->privdata); } memset(c, 0xff, sizeof(*c)); free(c);
}
//释放redisConnect()所产生的连接。
好,我们继续往下看测试代码:
/* PING server */ reply = redisCommand(c,"PING"); //注5: printf("PING: %s\n", reply->str); freeReplyObject(reply); //注6:
插入:redisCommand
注5:
void *redisCommand(redisContext *c, const char *format, ...) { va_list ap; va_start(ap,format); void *reply = redisvCommand(c,format,ap); va_end(ap); return reply;
}
//该函数用于执行redis数据库中的命令,第一个参数为连接数据库返回的redisContext,剩下的参数为变参.。
//此函数的返回值为void*,但是一般会强制转换为redisReply类型,以便做进一步的处理。
注6:freeReplyObject
/* Free a reply object */
void freeReplyObject(void *reply) { redisReply *r = reply; size_t j; if (r == NULL) return; switch(r->type) { case REDIS_REPLY_INTEGER: break; /* Nothing to free */ case REDIS_REPLY_ARRAY: case REDIS_REPLY_MAP: case REDIS_REPLY_SET: if (r->element != NULL) { for (j = 0; j < r->elements; j++) freeReplyObject(r->element[j]); free(r->element); } break; case REDIS_REPLY_ERROR: case REDIS_REPLY_STATUS: case REDIS_REPLY_STRING: case REDIS_REPLY_DOUBLE: free(r->str); break; } free(r);
}
//释放redisCommand执行后返回的的redisReply所占用的内存。
继续往下:
/* Set a key */ reply = redisCommand(c,"SET %s %s", "foo", "hello world"); printf("SET: %s\n", reply->str); freeReplyObject(reply); /* Set a key using binary safe API */ reply = redisCommand(c,"SET %b %b", "bar", (size_t) 3, "hello", (size_t) 5); printf("SET (binary API): %s\n", reply->str); freeReplyObject(reply); /* Try a GET and two INCR */ reply = redisCommand(c,"GET foo"); printf("GET foo: %s\n", reply->str); freeReplyObject(reply); reply = redisCommand(c,"INCR counter"); printf("INCR counter: %lld\n", reply->integer); freeReplyObject(reply); /* again ... */ reply = redisCommand(c,"INCR counter"); printf("INCR counter: %lld\n", reply->integer); freeReplyObject(reply); /* Create a list of numbers, from 0 to 9 */ reply = redisCommand(c,"DEL mylist"); freeReplyObject(reply); for (j = 0; j < 10; j++) { char buf[64]; snprintf(buf,64,"%u",j); reply = redisCommand(c,"LPUSH mylist element-%s", buf); freeReplyObject(reply); } /* Let's check what we have inside the list */ reply = redisCommand(c,"LRANGE mylist 0 -1"); if (reply->type == REDIS_REPLY_ARRAY) { for (j = 0; j < reply->elements; j++) { printf("%u) %s\n", j, reply->element[j]->str); } } freeReplyObject(reply); /* Disconnects and frees the context */ redisFree(c); return 0;
}
最后运行出来的结果呢:
若有需要完整测试代码,可以私信我哦
文章来源: lion-wu.blog.csdn.net,作者:看,未来,版权归原作者所有,如需转载,请联系作者。
原文链接:lion-wu.blog.csdn.net/article/details/108616681
【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)