Hiredis源码解析
Hiredis库主要包含三类API:同步api、异步api以及回复解析api。首先介绍一下同步api以及回复解析api。
1、同步api
1.1、建立tcp连接
函数原型:
redisContext
*
redisConnect
(
const
char
*
ip
,
int port
)
;
redisConnect函数用来创建一个上下文结构redisContext,并向reids服务器发起连接请求。源码如下所示:
redisContext
*
redisConnect
(
const
char
*
ip
,
int port
)
{
redisContext
*
c
;
c
=
redisContextInit
(
)
;
if
(
c
==
NULL
)
return
NULL
;
c
-
>
flags
|=
REDIS_BLOCK
;
redisContextConnectTcp
(
c
,
ip
,
port
,
NULL
)
;
return
c
;
}
其中redisConext用来保存与redis服务器连接状态相关信息、输出缓冲区以及回复解析器。结构如下所示:
typedef struct redisContext
{
int err
;
char errstr
[
128
]
;
int fd
;
int flags
;
char
*
obuf
;
redisReader
*
reader
;
...
}
redisContext
;
其中fd表示与redis服务器建立连接的socket描述符;而flag表示客户端标志位,表示客户端当前的状态;obuf用来保存输出缓存,用户调用reidsCommand向redis发送命令时,命令字符串首先会被追加到obuf中;reader是一个回复解析器,后续会介绍。
1.2 发送命令 & 接收回复
函数原型:
void
*
redisCommand
(
redisContext
*
c
,
const
char
*
format
,
...
)
;
redisCommand函数返回NULL表示有错误发生,可以通过检查redisContext中的err得到错误类型;如果执行完成,则返回值是一个redisReply指针,包含了Redis的恢复信息。
redisCommand主要通过redisvCommand实现,而redisvCommand主要是通过redisvAppendCommand和__redisBlockForReply两个实现。
redisvAppendCommand源码如下所示:
int
redisvAppendCommand
(
redisContext
*
c
,
const
char
*
format
,
va_list ap
)
{
...
len
=
redisvFormatCommand
(
&
cmd
,
format
,
ap
)
;
if
(
len
==
-
1
)
{
__redisSetError
(
c
,
REDIS_ERR_OOM
,
"Out of memory"
)
;
return
REDIS_ERR
;
}
else
if
(
len
==
-
2
)
{
__redisSetError
(
c
,
REDIS_ERR_OTHER
,
"Invalid format string"
)
;
return
REDIS_ERR
;
}
if
(
__redisAppendCommand
(
c
,
cmd
,
len
)
!=
REDIS_OK
)
{
free
(
cmd
)
;
return
REDIS_ERR
;
}
...
}
redisvAppendCommand函数作用是解析用户的输入,并将用户输入的命令字符串转换成redis统一的格式,暂存到redisContext.obuf中。
__redisBlockForReply源码如下所示:
void
*
__redisBlockForReply
(
redisContext
*
c
)
{
void
*
reply
;
if
(
c
-
>
flags
&
REDIS_BLOCK
)
{
if
(
redisGetReply
(
c
,
&
reply
)
!=
REDIS_OK
)
return
NULL
;
return
reply
;
}
return
NULL
;
}
int
redisGetReply
(
redisContext
*
c
,
void
**
reply
)
{
if
(
redisGetReplyFromReader
(
c
,
&
aux
)
==
REDIS_ERR