Redis源码分析之anet网络通信的封装

anet是redis对tcp/ip网络中socket api接口的一个全面的封装,针对server/client端。封装的api的接口如下,注释了主要的接口:

// tcp连接
int anetTcpConnect(char *err, char *addr, int port);
// 非阻塞连接
int anetTcpNonBlockConnect(char *err, char *addr, int port);
// 非阻塞绑定
int anetTcpNonBlockBindConnect(char *err, char *addr, int port, char *source_addr);
// 非阻塞绑定
int anetTcpNonBlockBestEffortBindConnect(char *err, char *addr, int port, char *source_addr);
//unix socket connect
int anetUnixConnect(char *err, char *path);
// unix non-block connect 
int anetUnixNonBlockConnect(char *err, char *path);
// socket读数据
int anetRead(int fd, char *buf, int count);
// 解析所有的东西
int anetResolve(char *err, char *host, char *ipbuf, size_t ipbuf_len);
// 解析ip
int anetResolveIP(char *err, char *host, char *ipbuf, size_t ipbuf_len);
// ipv4下socket()函数创建socket
int anetTcpServer(char *err, int port, char *bindaddr, int backlog);
// ipv6下create socket
int anetTcp6Server(char *err, int port, char *bindaddr, int backlog);
// unix create socket and bind
int anetUnixServer(char *err, char *path, mode_t perm, int backlog);
// tcp socket accept()
int anetTcpAccept(char *err, int serversock, char *ip, size_t ip_len, int *port);
// unix socket accept()
int anetUnixAccept(char *err, int serversock);
// socket write data to buffer
int anetWrite(int fd, char *buf, int count);
// set socket to non-block mode
int anetNonBlock(char *err, int fd);
// set socket to block mode
int anetBlock(char *err, int fd);
// set socket mode to tcp_nodelay
int anetEnableTcpNoDelay(char *err, int fd);
// shutdown tcp_nodelay mode
int anetDisableTcpNoDelay(char *err, int fd);
// open keepalive mode
int anetTcpKeepAlive(char *err, int fd);
// set socket send timeout value
int anetSendTimeout(char *err, int fd, long long ms);
int anetPeerToString(int fd, char *ip, size_t ip_len, int *port);
int anetKeepAlive(char *err, int fd, int interval);
// get socket port and name
int anetSockName(int fd, char *ip, size_t ip_len, int *port);
int anetFormatAddr(char *fmt, size_t fmt_len, char *ip, int port);
int anetFormatPeer(int fd, char *fmt, size_t fmt_len);
int anetFormatSock(int fd, char *fmt, size_t fmt_len);

根据上面的接口名称和注释,做过网络编程的同学就能很快发现redis的anet部分只是对tcp socket api接口的一次封装。

其中有几个主要的方法根据我自己的理解进行分析:

设置tcp_nodelay的方法包装成了连个接口,分别是打开与关闭

static int anetSetTcpNoDelay(char *err, int fd, int val)
{
    if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1)
    {
        anetSetError(err, "setsockopt TCP_NODELAY: %s", strerror(errno));
        return ANET_ERR;
    }
    return ANET_OK;
}
int anetEnableTcpNoDelay(char *err, int fd)
{
    return anetSetTcpNoDelay(err, fd, 1);
}

int anetDisableTcpNoDelay(char *err, int fd)
{
    return anetSetTcpNoDelay(err, fd, 0);
}

使用者根据自己的实际情况选择合适的调用接口。

里面有个ipv4和ipv6的考虑挺周全的,接口如下:

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 */

	// hostname info
    if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) {
        anetSetError(err, "%s", gai_strerror(rv));
        return ANET_ERR;
    }
    if (info->ai_family == AF_INET) {
		// ipv4
		struct sockaddr_in *sa = (struct sockaddr_in *)info->ai_addr;
        inet_ntop(AF_INET, &(sa->sin_addr), ipbuf, ipbuf_len);
    } else {
		// IPv6的解法
		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;
}

一般情况下,自己编程时只考虑到了ipv4的情况,但是未考虑ipv6的情况,现在看这些代码觉得作者还是挺细心周到的。

总体感觉这部分内容比较容易,暂时写到这里。

你可能感兴趣的:(C,数据库,分布式,redis)