redis源码分析(六)- anet网络通讯的封装

一 anet网络通讯封装介绍

    Redis对网络通讯的封装在代码anet.c里面,总的来说该封装是对标准的socket的TCP通讯模块的一个小小的封装,总代码量才600多行。

二 代码实现分析

    因为代码简单,先大致看一下它的API

int anetTcpConnect(char *err, char *addr, int port); /* TCP的默认连接 */  
int anetTcpNonBlockConnect(char *err, char *addr, int port); /* TCP的非阻塞连接 */  
int anetUnixConnect(char *err, char *path); /* anet的Unix方式的默认连接方式 */  
int anetUnixNonBlockConnect(char *err, char *path); /* anet的Unix方式的非阻塞连接方式 */  
int anetRead(int fd, char *buf, int count); /* anet网络读取文件到buffer中操作 */  
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len); /* 解析所有的东西 */  
int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len); /* 单单解析IP的地址 */  
int anetTcpServer(char *err, int port, char *bindaddr, int backlog);  
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog);  
int anetUnixServer(char *err, char *path, mode_t perm, int backlog);  
int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);  
int anetUnixAccept(char *err, int serversock);  
int anetWrite(int fd, char *buf, int count); /* anet通过网络从buffer中写入文件操作 */  
int anetNonBlock(char *err, int fd); /* anet设置非阻塞的方法 */  
int anetEnableTcpNoDelay(char *err, int fd); /* 启用TCP没有延迟 */  
int anetDisableTcpNoDelay(char *err, int fd); /* 禁用TCP连接没有延迟 */  
int anetTcpKeepAlive(char *err, int fd); /* 设置TCP保持活跃连接状态。适用于所有系统 */  
int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);  
int anetKeepAlive(char *err, int fd, int interval); /* 设置TCP连接一直存活,用来检测已经死去的结点,interval选项只适用于Linux下的系统 */  
int anetSockName(int fd, char *ip, size_t ip_len, int *port);  

    这里面的实现代码我们都能找到熟悉的函数,例如fcntl、read、write、getaddrinfo等等,总的感觉就是作者仅仅是对C语言的socket标准通讯的一次简单的封装,里面的代码都是对这些函数的简单的调用,没有过多的复杂的操作。比如说下面这个非阻塞的设置:

/*
 * 将 fd 设置为非阻塞模式(O_NONBLOCK)
 */
int anetNonBlock(char *err, int fd)
{
    int flags;

    /* Set the socket non-blocking.
     * Note that fcntl(2) for F_GETFL and F_SETFL can't be
     * interrupted by a signal. */
    if ((flags = fcntl(fd, F_GETFL)) == -1) {
        anetSetError(err, "fcntl(F_GETFL): %s", strerror(errno));
        return ANET_ERR;
    }
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
        anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
        return ANET_ERR;
    }
    return ANET_OK;
}
可以在以下代码调用是否阻塞:

/*
 * 创建阻塞 TCP 连接
 */
int anetTcpConnect(char *err, char *addr, int port)
{
    return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONE);
}

/*
 * 创建非阻塞 TCP 连接
 */
int anetTcpNonBlockConnect(char *err, char *addr, int port)
{
    return anetTcpGenericConnect(err,addr,port,NULL,ANET_CONNECT_NONBLOCK);
}

对ip地址有ipv4和ipv6地址不同的处理方法。这个作者想得还是非常全面的。在对地址做resolve解析的时候就考虑到了这个问题:

/* anetGenericResolve() is called by anetResolve() and anetResolveIP() to
 * do the actual work. It resolves the hostname "host" and set the string
 * representation of the IP address into the buffer pointed by "ipbuf".
 *
 * If flags is set to ANET_IP_ONLY the function only resolves hostnames
 * that are actually already IPv4 or IPv6 addresses. This turns the function
 * into a validating / normalizing function. */
// 解释 host 的地址,并保存到 ipbuf 中
int anetGenericResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len,
                       int flags)
{
    struct addrinfo hints, *info;
    int rv;

    memset(&hints,0,sizeof(hints));
    if (flags & ANET_IP_ONLY) hints.ai_flags = AI_NUMERICHOST;
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;  /* specify socktype to avoid dups */

    if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) {
        anetSetError(err, "%s", gai_strerror(rv));
        return ANET_ERR;
    }
    if (info->ai_family == AF_INET) {
        struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr;
        inet_ntop(AF_INET, &(sa->sin_addr), ipbuf, ipbuf_len);
    } else {
        struct sockaddr_in6 *sa = (struct sockaddr_in6 *)info->ai_addr;
        inet_ntop(AF_INET6, &(sa->sin6_addr), ipbuf, ipbuf_len);
    }

    freeaddrinfo(info);
    return ANET_OK;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值