美文网首页
redis网络连接

redis网络连接

作者: 剑雪封侯之 | 来源:发表于2018-12-16 22:54 被阅读0次

客户端定义

redis使用了一对多服务器程序:一个服务器可以与多个客户端进行网络连接,向多个客户端提供服务。服务端为客户端建立的相应的客户端结构来保存客户端的相关信息,位于文件redis.h中。

typedef struct redisClient {
    uint64_t id;            /* Client incremental unique ID. */
    //客户端的套接字,伪客户端的为-1(AOF,Lua脚本),其它为普通客户端
    int fd;
    //客户端正在使用的redis数据库指针
    redisDb *db;
    int dictid;
    //客户端的名字,使用client setname 来设置名称
    robj *name;             /* As set by CLIENT SETNAME */
    //输入缓存区
    sds querybuf;
    size_t querybuf_peak;   /* Recent (100ms or more) peak of querybuf size */
    //将querybuf中解析完成后,放入argv中,个数放于argc中
    int argc;
    robj **argv;
    //redis 命令的实现函数
    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;
    //redis标志位
    int flags;              /* REDIS_SLAVE | REDIS_MONITOR | REDIS_MULTI ... */
    //身份验证,0表示未通过身份验证,1表示通过身份验证。仅在服务端启用了安全验证时才用,若启用
    //未通过验证,则只能使用AUTH命令,其它均无法使用
    int authenticated;      /* when requirepass is non-NULL */
    int replstate;          /* replication state if this is a slave */
    int repldbfd;           /* replication DB file descriptor */
    off_t repldboff;        /* replication DB file offset */
    off_t repldbsize;       /* replication DB file size */
    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 */
    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 */
    multiState mstate;      /* MULTI/EXEC state */
    blockingState bpop;   /* blocking state */
    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;
    //默认大小为16k
    char buf[REDIS_REPLY_CHUNK_BYTES];
} redisClient;

服务端接受客户端连接

void initServer(void) {
   ...
    //创建evenloop
   server.el = aeCreateEventLoop(server.maxclients+REDIS_EVENTLOOP_FDSET_INCR);
    ...
    //创建socket监听套接字
    if (server.port != 0 &&
        listenToPort(server.port,server.ipfd,&server.ipfd_count) == REDIS_ERR)
        exit(1);
    ...
    //增加网络套接字的监听,收到可读事件后,接受连接
    for (j = 0; j < server.ipfd_count; j++) {
        if (aeCreateFileEvent(server.el, server.ipfd[j], AE_READABLE,
            acceptTcpHandler,NULL) == AE_ERR)
            {
                redisPanic(
                    "Unrecoverable error creating server.ipfd file event.");
            }
    }
   ... 
}

//接受tcp连接
void acceptTcpHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    int cport, cfd, max = MAX_ACCEPTS_PER_CALL;
    char cip[REDIS_IP_STR_LEN];
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(mask);
    REDIS_NOTUSED(privdata);

    while(max--) {
        //接受连接
        cfd = anetTcpAccept(server.neterr, fd, cip, sizeof(cip), &cport);
        if (cfd == ANET_ERR) {
            if (errno != EWOULDBLOCK)
                redisLog(REDIS_WARNING,
                    "Accepting client connection: %s", server.neterr);
            return;
        }
        redisLog(REDIS_VERBOSE,"Accepted %s:%d", cip, cport);
        //根据fd生成客户端结构
        acceptCommonHandler(cfd,0);
    }
}
//接受本地套接字的连接
void acceptUnixHandler(aeEventLoop *el, int fd, void *privdata, int mask) {
    int cfd, max = MAX_ACCEPTS_PER_CALL;
    REDIS_NOTUSED(el);
    REDIS_NOTUSED(mask);
    REDIS_NOTUSED(privdata);

    while(max--) {
        cfd = anetUnixAccept(server.neterr, fd);
        if (cfd == ANET_ERR) {
            if (errno != EWOULDBLOCK)
                redisLog(REDIS_WARNING,
                    "Accepting client connection: %s", server.neterr);
            return;
        }
        redisLog(REDIS_VERBOSE,"Accepted connection to %s", server.unixsocket);
        acceptCommonHandler(cfd,REDIS_UNIX_SOCKET);
    }
}

//根据连接的文件描述符创建一个客户端
static void acceptCommonHandler(int fd, int flags) {
    redisClient *c;
    if ((c = createClient(fd)) == NULL) {
        redisLog(REDIS_WARNING,
            "Error registering fd event for the new client: %s (fd=%d)",
            strerror(errno),fd);
        close(fd); /* May be already closed, just ignore errors */
        return;
    }
    /* If maxclient directive is set and this is one client more... close the
     * connection. Note that we create the client instead to check before
     * for this condition, since now the socket is already set in non-blocking
     * mode and we can send an error for free using the Kernel I/O */
     //如果超过最大的客户端个数,则向客户端发送错误原因,同时关闭该连接
    if (listLength(server.clients) > server.maxclients) {
        char *err = "-ERR max number of clients reached\r\n";

        /* That's a best effort error message, don't check write errors */
        if (write(c->fd,err,strlen(err)) == -1) {
            /* Nothing to do, Just to avoid the warning... */
        }
        server.stat_rejected_conn++;
        freeClient(c);
        return;
    }
    server.stat_numconnections++;
    c->flags |= flags;
}

相关文章

  • Redis系列-Redis客户端及Redis基本知识

    四、Redis客户端 Redis客户端是一个程序,通过网络连接到Redis服务器,从而实现跟 Redis服务器的交...

  • redis网络连接

    客户端定义 redis使用了一对多服务器程序:一个服务器可以与多个客户端进行网络连接,向多个客户端提供服务。服务端...

  • redis主从复制----源码实现

    redis的复制实现包括了以下几个过程 主从关系建立 主从网络连接建立 发送PING命令 认证权限 发送端口号 发...

  • 使用 try-with-resources 优雅关闭资源

    我们知道,在 Java 编程过程中,如果打开了外部资源(文件、数据库连接、网络连接等、redis),我们必须在这些...

  • Redis设计 - 服务器

    前言 Redis服务器负责与多个客户端建立网络连接,并处理客户端的请求,通过资源管理来维持服务器自身的运转。 命令...

  • Centos7修改DNS

    显示当前网络连接nmcli connection show 修改当前网络连接对应的DNS服务器,这里的网络连接可以...

  • Redis之服务器

    Redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的数据,...

  • Redis命令请求的执行过程

    前言 Redis服务器负责与多个客户端建立网络连接,处理客户端发送的命令请求,在数据库中保存客户端执行命令所产生的...

  • iOS网络层设计

    iOS网络层设计 总体思想:提供稳定的数据服务:稳定的网络连接+稳定的数据接口。 稳定的网络连接:网络连接尽量做到...

  • iOS下的实际网络连接状态检测

    iOS下的实际网络连接状态检测 iOS下的实际网络连接状态检测

网友评论

      本文标题:redis网络连接

      本文链接:https://www.haomeiwen.com/subject/ybuxkqtx.html