Más información sobre hiredis: operación redis de C ++

Inserte la descripción de la imagen aquí

Este artículo no establece una tabla de contenido por el momento, porque realmente no sé cómo configurarlo.

Como hiredis es una biblioteca dinámica, no sabía por dónde empezar desde el principio. Afortunadamente, los desarrolladores proporcionaron algunos casos de prueba, así que seguiré los pasos de los casos de prueba para analizarlos y aprender.

Si desea comenzar rápidamente, puede usar este tutorial: Aplique lo que ha aprendido: el funcionamiento de Redis en C ++
no necesita dedicar demasiado tiempo a este artículo. Recopile y léalo más tarde.

Si necesita un ejemplo completo, puede enviarme un mensaje privado.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <hiredis.h>	

Este es el archivo de encabezado, #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;

Insertar:
Nota 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;

Bien, sigamos mirando el código de muestra.

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);
    }

Insertar:
Nota 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()所产生的连接。

Ok, continuemos mirando el código de prueba:

 /* PING server */
    reply = redisCommand(c,"PING");	//注5:
    printf("PING: %s\n", reply->str);
    freeReplyObject(reply);	//注6:

Insertar: redisCommand
Nota 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类型,以便做进一步的处理。

Nota 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所占用的内存。

Continuar hacia abajo:

 /* 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;
}

El resultado de la operación final:
Inserte la descripción de la imagen aquí

Si necesita un código de prueba completo, puede enviarme un mensaje privado

Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/qq_43762191/article/details/108616681
Recomendado
Clasificación