Some time ago, when I learned about Redis, I heard the name of hiredis, And I was just doing asynchronous learning. I went to the Code to learn it. I almost don't know much about C. It is limited to the simplest syntax and has never been written in the production environment. So I should first look at the simple code of the Client. Next time I look at the Memcached code, it should be smoother. Hiredis is written in C.
Some time ago, when I learned about Redis, I heard the name of hiredis, And I was just doing asynchronous learning. I went to the Code to learn it. I almost don't know much about C. It is limited to the simplest syntax and has never been written in the production environment. So I should first look at the simple code of the Client. Next time I look at the Memcached code, it should be smoother. Hiredis is written in C.
Some time ago, when I learned about Redis, I heard the name of hiredis, And I was just doing asynchronous learning. I went to the Code to learn it. I almost don't know much about C. It is limited to the simplest syntax and has never been written in the production environment. So I should first look at the simple code of the Client. Next time I look at the Memcached code, it should be smoother.
Hiredis is a Redis client written in C. It encapsulates the Redis protocol and provides two APIs, synchronous and asynchronous. The Hiredis code is located at https://github.com/redis/hiredis.
One-minute entry
Synchronous API call method:
redisContext *context = redisConnect("127.0.0.1", 6379);reply = redisCommand(context, "SET foo %s", value); printf("PING: %s\n", reply->str);freeReplyObject(reply)redisFree(context);
The call method of Redis AE asynchronous API uses Redis's own AE event library. For details about why Redis does not use libevent or libev, refer to Reason:
void connectCallback(const redisAsyncContext *c, int status) { printf("Connected...\n");}void disconnectCallback(const redisAsyncContext *c, int status) { printf("Disconnected...\n");}void getCallback(redisAsyncContext *c, void *r, void *privdata) { redisReply *reply = r; if (reply == NULL) return; printf("argv[%s]: %s\n", (char*)privdata, reply->str); redisAsyncDisconnect(c);}redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);loop = aeCreateEventLoop();redisAeAttach(loop, c);redisAsyncSetConnectCallback(c,connectCallback);redisAsyncSetDisconnectCallback(c,disconnectCallback);redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
Libev asynchronous API call becauseadapters/*.h
Encapsulation is good, so it is almost the same as AE call:
void connectCallback(const redisAsyncContext *c, int status) { printf("Connected...\n");}void disconnectCallback(const redisAsyncContext *c, int status) { printf("Disconnected...\n");}void getCallback(redisAsyncContext *c, void *r, void *privdata) { redisReply *reply = r; if (reply == NULL) return; printf("argv[%s]: %s\n", (char*)privdata, reply->str); /* Disconnect after receiving the reply to GET */ redisAsyncDisconnect(c);}redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379);redisLibevAttach(EV_DEFAULT_ c);redisAsyncSetConnectCallback(c,connectCallback);redisAsyncSetDisconnectCallback(c,disconnectCallback);redisAsyncCommand(c, getCallback, (char*)"end-1", "GET key");
Hiredis also supports libevent, which I will not list.
For more information, see https://github.com/redis/hiredis/tree/master/examples.
Main Structure
- RedisReply
- RedisReader
- RedisContext
Process Synchronization connection
The code for synchronous connection is inhiredis.c
Andnet.c
.
redisConnect
/redisConnectWithTimeout
/redisConnectNonBlock
All callednet.c
InsideredisContextConnectTcp
. Usefcntl(fd, F_SETFL, flags)
Set whether to block the connection.
O_NONBLOCK
That is, the Socket is not blocked, but it is still synchronized.
In fact, hiredis uses non-blocking (poll) Methods no matter whether it is blocked or not.connect
When you connect to the server,-1 is returned anderrno
IsEINPROGRESS
, Which is normal in non-blocking mode. Why is the blocking mode forced to use non-blocking?poll
Connection? To support the timeout function. After the connection is successful, hiredis is reset to blocking or non-blocking mode as required.
For details about how to design the timeout function, refer to http://blog.csdn.net/ast_224/article/details/2957294.
Command
Using va_list to solve the problem of variable parameters (C also supports variable-length parameters, and I was shocked. I was really C blind ).
int redisFormatCommand(char **target, const char *format, ...) { va_list ap; int len; va_start(ap,format);}
redisvCommand
Used to execute the Redis blocking command. It will call__redisBlockForReply
, Internal callredisBufferWrite
Write the buffer from the socket, and then wait synchronously.redisBufferRead
Read data,redisGetReplyFromReader
Parse the returned data.
Asynchronous connection
The code for asynchronous calling is inasync.c
.
The important structure isredisAsyncContext
AndredisAeEvents
The important method of the former is to register the callback function:addRead
/delRead
/addWrite
/delWrite
The latter is used to store loop/fd/event stream.
During asynchronous connectionredisContextConnectTcp
Non-blocking connection to the server.
UseaeCreateEventLoop
Create an event loop and then useredisAeAttach
Tocontext
Register events, suchaeCreateFileEvent(loop,e->fd,AE_READABLE,redisAeReadEvent,e)
Registerread
Event, and set the callback callredisAeReadEvent
,redisAeReadEvent
Then host this eventredisAsyncHandleRead
(Defined in async. c and called by three event libraries ).
Therefore, hiredis uses the adapter encapsulation to shield the API differences between AE, libevent, and libev, so that you can choose flexibly. It is said that AE was rewritten from two libevent libraries, but I think the style of AE is similar to that of libev, while the style of libevent is better understood.
If we compare the complexity of the Code with the IOLoop of Tornado, we can see that the API encapsulation of Tornado is too user-friendly, and the code of C is complicated to write, system APIs, resource control, and error control are all troublesome.
For details about the Redis AE event library, refer to http://my.oschina.net/u/917596/blog/16107720.osc_h4_6. Libevent a simple tutorial http://www.wangafu.net /~ Nickm/libevent-book/01_intro.html.
About C
As a C scum, I barely read hiredis. I feel that the C foundation is not enough. I will list some of the doubts in the learning process:
IFDEF
Use, can prevent repeated import of the same head file definition, here there is a detailed explanation http://faculty.cs.niu.edu /~ Mcmahon/CS241/c241man/node90.html
__cplusplus
: C ++ defines this variable, but C does not. Therefore, when the C ++ compiler recognizes the sourceifdef
To useextern
Compile C code.
- Long: long can only store 32 bits. long can store 64 bits, that is, 0-2 ^ 64-1.
c->flags |= REDIS_BLOCK
/c->flags &= ~REDIS_BLOCK;
Simple bit operations.
- Sds (simple dynamic string) is a C String structure implemented by Redis itself.
((void)fd)
It seems that the fd pointer is converted to a non-typed pointer, and it is of no use.
Link: http://blog.log4d.com/2014/03/hiredis/
3a1ff193cee606bd1e2ea554a16316ee