Redis 设计与实现(第十三章) -- 客户端
概述
对于每个与服务器连接的客户端,服务器都为它创建相应的redisClient的数据结构,并保持了相应的状态。Redis Server通过一个链表来保存所有的客户端连接。
本章包括:
- 客户端数据结构介绍;
- 客户端的创建与关闭
数据结构
先来看下redisClient中的数据结构:
* With multiplexing we need to take per-client state.
* Clients are taken in a linked list. */
typedef struct redisClient {
uint64_t id; /* Client incremental unique ID. */
int fd; //套接字描述符,大于1的整数,如果是伪客户端则为-1
redisDb *db; //redisDB
int dictid;
robj *name; /* As set by CLIENT SETNAME 客户端名字*/
sds querybuf; //输入缓冲区,用于保存客户端发送的命令请求
size_t querybuf_peak; /* Recent (100ms or more) peak of querybuf size */
int argc; //命令参数长度
robj **argv; //要执行的命令及命令参数
struct redisCommand *cmd, *lastcmd; //命令实现
int reqtype;
int multibulklen; /* number of multi bulk arguments left to read */
long bulklen; /* length of bulk argument in multi bulk request */
list *reply;
unsigned long reply_bytes; /* Tot bytes of objects in reply list */
int sentlen; /* Amount of bytes already sent in the current
buffer or object being sent. */
time_t ctime; /* Client creation time ,客户端创建时间*/
time_t lastinteraction; /* time of the last interaction, used for timeout */
time_t obuf_soft_limit_reached_time;
int flags; /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... 客户端角色,一些状态*/
int authenticated; /* when requirepass is non-NULL 认证*/
int replstate; /* replication state if this is a slave */
int repl_put_online_on_ack; /* Install slave write handler on ACK. */
int repldbfd; /* replication DB file descriptor */
off_t repldboff; /* replication DB file offset */
off_t repldbsize; /* replication DB file size */
sds replpreamble; /* replication DB preamble. */
long long reploff; /* replication offset if this is our master */
long long repl_ack_off; /* replication ack offset, if this is a slave */
long long repl_ack_time;/* replication ack time, if this is a slave */
long long psync_initial_offset; /* FULLRESYNC reply offset other slaves
copying this slave output buffer
should use. */
char replrunid[REDIS_RUN_ID_SIZE+1]; /* master run id if this is a master */
int slave_listening_port; /* As configured with: SLAVECONF listening-port */
int slave_capa; /* Slave capabilities: SLAVE_CAPA_* bitwise OR. */
multiState mstate; /* MULTI/EXEC state */
int btype; /* Type of blocking op if REDIS_BLOCKED. */
blockingState bpop; /* blocking state */
long long woff; /* Last write global replication offset. */
list *watched_keys; /* Keys WATCHED for MULTI/EXEC CAS */
dict *pubsub_channels; /* channels a client is interested in (SUBSCRIBE) */
list *pubsub_patterns; /* patterns a client is interested in (SUBSCRIBE) */
sds peerid; /* Cached peer ID. */
/* Response buffer,输出缓冲区 */
int bufpos; //记录了buf目前已使用的字节数
char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;
客户端创建与关闭
创建普通客户端
当客户端连接服务器时,服务器就会调用相应的连接事件处理器,将连接的客户端状态添加到redisServer数据结构中clients链表的末尾。
如下:
关闭普通客户端
一个普通客户端可能因为多种原因被关闭:
1.如果客户端进程退出或杀死,那么客户端与服务器间的网络连接将会断开,造成客户端关闭;
2.如果客户端向服务器发送了不符合协议格式的命令请求,那么这个客户端也会被服务器关闭;
3.如果客户端成了client kill命令的目标,那么客户端也将会被关闭;
4.如果用户为服务器设置了超时时间,那么超时时间到后,客户端也将会被关闭,在主从服务器里面有一些例外;
5.如果客户端发送的命令超过了缓冲区的大小(默认为1GB),那么客户端也将被关闭;
6.如果要发送给客户端的回复命令超过了输出缓冲区的大学,那么这个客户端也将被服务器关闭。
伪客户端
1.Lua脚本的伪客户端,在服务器运行期间一直存在,直到服务器关闭;
2.AOF加载的伪客户端,在AOF加载完成后,伪客户端就关闭连接。