最新消息:比度技术-是关注互联网技术的个人博客,大部分内容来自互联网,以作为笔记查阅。

Redis源码分析之-Redis服务器与客户端间的交互

分布式存储 bidu 152浏览

服务器都为这些客户端建立了相应的redisClient结构,该结构体定义在redis.h中

解析处理客户端命令:processMultibulkBuffer

回复客户端:服务器执行完相应的命令处理函数之后,就会调用addReply类的函数将要回复给客户端的信息写入客户端输出缓存。这些函数包括addReply,addReplySds,addReplyError,addReplyStatus等。 这些函数首先都会调用prepareClientToWrite函数,注册socket描述符上的可写事件,然后将回复信息写入到客户端输出缓存中。

Redis3.0 .5- prepareClientToWrite 里面有注册客户端写事件。

/* Try to install the write handler. */

if (aeCreateFileEvent(server.el, c->fd, AE_WRITABLE,

sendReplyToClient, c) == AE_ERR)

{

freeClientAsync(c);

return REDIS_ERR;

}

如果当前客户端是Lua客户端,直接返回REDIS_OK,而无需注册socket描述符上的可写事件,因为根本没有socket描述符;

如果客户端为Master节点,除非设置REDIS_MASTER_FORCE_REPLY标志,否则这种客户端不接收回复,因此直接返回REDIS_ERR;

如果客户端的socket描述符小于等于0,说明是加载AOF文件时的伪客户端,直接返回REDIS_ERR;

如果是普通客户端,或者是在从节点需要接收数据时,如果此前从未注册过socket上的可写事件,则调用aeCreateFileEvent注册socket描述符c->fd上的可写事件,事件回调函数为sendReplyToClient;最后直接返回REDIS_OK;

但是redis4.0.9 里面没有看到注册代码;而是调用:

listAddNodeHead(server.clients_pending_write,c);

当TCP输出缓冲区有一定剩余空间时,socket描述符上的可写事件就会触发,从而调用事件回调函数sendReplyToClient。该函数调用write,将输出缓存中的数据发送出去。

void sendReplyToClient(aeEventLoop *el, int fd, void *privdata, int mask) {

UNUSED(el);

UNUSED(mask);

writeToClient(fd,privdata,1);

}

Redis4.0.9:

handleClientsWithPendingWrites:代码如下:

int handleClientsWithPendingWrites(void) {

listIter li;

listNode *ln;

int processed = listLength(server.clients_pending_write);

 

listRewind(server.clients_pending_write,&li);

while((ln = listNext(&li))) {

client *c = listNodeValue(ln);

c->flags &= ~CLIENT_PENDING_WRITE;

listDelNode(server.clients_pending_write,ln);

 

/* Try to write buffers to the client socket. */

if (writeToClient(c->fd,c,0) == C_ERR) continue;

 

/* If after the synchronous writes above we still have data to

* output to the client, we need to install the writable handler. */

if (clientHasPendingReplies(c)) {

int ae_flags = AE_WRITABLE;

/* For the fsync=always policy, we want that a given FD is never

* served for reading and writing in the same event loop iteration,

* so that in the middle of receiving the query, and serving it

* to the client, we’ll call beforeSleep() that will do the

* actual fsync of AOF to disk. AE_BARRIER ensures that. */

if (server.aof_state == AOF_ON &&

server.aof_fsync == AOF_FSYNC_ALWAYS)

{

ae_flags |= AE_BARRIER;

}

if (aeCreateFileEvent(server.el, c->fd, ae_flags,

sendReplyToClient, c) == AE_ERR)

{

freeClientAsync(c);

}

}

}

return processed;

}

 

/* This function gets called every time Redis is entering the

* main loop of the event driven library, that is, before to sleep

* for ready file descriptors. */

void beforeSleep(struct aeEventLoop *eventLoop) ;该函数调用

/* Handle writes with pending output buffers. */

handleClientsWithPendingWrites(); 向客户端写数据。

 

 

void aeMain(aeEventLoop *eventLoop) {

eventLoop->stop = 0;

while (!eventLoop->stop) {

if (eventLoop->beforesleep != NULL)

eventLoop->beforesleep(eventLoop);

aeProcessEvents(eventLoop, AE_ALL_EVENTS|AE_CALL_AFTER_SLEEP);

}

}

 

 

 

 

参考:https://blog.csdn.net/gqtcgq/article/details/51106120

转载请注明:比度技术-关注互联网技术的个人博客 » Redis源码分析之-Redis服务器与客户端间的交互