关闭

Redis源码分析(二十一)--- anet网络通信的封装

标签: nosql数据库内存数据库网络通信
3835人阅读 评论(0) 收藏 举报
分类:

           昨天非常轻松的分析完Redis的事件驱动模型之后,今天我来看看anet的代码,anet是Redis对于Client/Server的网络操作的一个小小封装。代码中对此文件的官方解释为:

/* anet.c -- Basic TCP socket stuff made a bit less boring
 * 基于简单的基本TCP的socket连接
后面的made a bit less boring这在这里表示啥意思,就让我有点费解了,不过前面的是重点,Basic TCP Socket,基于的是TCP 协议的socket连接。anet.h的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);
我们还是能够看到很多熟悉的方法的,read,write,accept.connect等在任何编程语言中都会看到的一些方法。看完这个anet,最直观的感觉就是作者编写的这个网络操作库就是对于C语言系统网络库的又一次简答的封装,因为里面都是直接调用库方法的函数实现。作者根据自己业务的需要在上面做了小小的封装。比如说非阻塞的设置;

/* anet设置非阻塞的方法 */
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;
    }
    //调用fcntl方法设置非阻塞方法
    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;
}
fcntl方法是直接起作用的方法。在整个网络操作文件的中,让我感觉稍有亮点的还是有一些地方的

(1).能设置BLOCK连接还是NONE_BLOCKED方式的connect;

/* TCP的默认连接 */
int anetTcpConnect(char *err, char *addr, int port)
{
    return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
}

/* TCP的非阻塞连接 */
int anetTcpNonBlockConnect(char *err, char *addr, int port)
{
    return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
}
(2).能设置连接的Delay的延时与否。:

/* 设置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;
}

/* 启用TCP没有延迟 */
int anetEnableTcpNoDelay(char *err, int fd)
{
    return anetSetTcpNoDelay(err, fd, 1);
}

/* 禁用TCP连接没有延迟 */
int anetDisableTcpNoDelay(char *err, int fd)
{
    return anetSetTcpNoDelay(err, fd, 0);
}
也许在有些情况下对延时要求比较高,就不能有延时。

(3).对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主机名或IP地址 */
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
    if ((rv = getaddrinfo(host, NULL, &hints, &info)) != 0) {
        anetSetError(err, "%s", gai_strerror(rv));
        return ANET_ERR;
    }
    
    //根据类型解析ipV4的地址还是ipV6的地址
    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;
}
还有一些常见的方法,与我们平时写代码时用的手法基本一样,比如accept()的方法:

/* socket连接操作 */
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
    int fd;
    while(1) {
    	//通过while循环等待连接
        fd = accept(s,sa,len);
        if (fd == -1) {
            if (errno == EINTR)
                continue;
            else {
                anetSetError(err, "accept: %s", strerror(errno));
                return ANET_ERR;
            }
        }
        break;
    }
    return fd;
}

0
0
查看评论

anet 网络操作函数 redis

#ifndef ANET_H #define ANET_H #define ANET_OK 0 #define ANET_ERR -1 #define ANET_ERR_LEN 256 /* Flags used with certain functions. */ #define AN...
  • hintonic
  • hintonic
  • 2014-03-20 20:01
  • 877

Redis anet

anet.c -- Basic TCP socket stuff made a bit less boring. 这里接口很简洁,值得复用! // 返回socket int anetTcpConnect(char* err, char* addr, int port); int anetTc...
  • jollyjumper
  • jollyjumper
  • 2013-06-19 21:24
  • 1206

Redis源代码分析之四:Unix底层网络通信——Anet

还是先介绍接口: int anetTcpConnect(char *err, char *addr, int port); int anetTcpNonBlockConnect(char *err, char *addr, int port); int anetUnixConnect(char...
  • Aegeaner
  • Aegeaner
  • 2012-02-04 14:29
  • 3698

redis原理-网络框架

redis原理-网络框架 一、  流程 redis自己封装了一套网络框架AE框架,根据不同的系统封装了不同的实现,在linux下使用的是epoll事件模型。 在头文件config.h定义了根据当前系统环境使用的模型宏: /* Test for polling API */ #if...
  • xyblog
  • xyblog
  • 2016-02-17 09:31
  • 1451

Redis网络库源码分析(1)之介绍篇

一、前言Redis网络库是一个单线程EPOLL模型的网络库,和Memcached使用的libevent相比,它没有那么庞大,代码一共2000多行,因此比较容易分析。其实网上已经有非常多有关这个网络库的分析了,但是我觉得它们的不足在于只是分析了各个文件中各个函数的单独含义,而没有将其统一起来,不能给读...
  • yangbodong22011
  • yangbodong22011
  • 2017-03-23 15:30
  • 1010

redis anet网络通信的源码分析

anet是redis对网络通信(socket)的简单封装和一些状态设置的封装。
  • wade1991
  • wade1991
  • 2017-01-05 23:19
  • 426

Redis 的 C++开发包 使用例子

http://blog.csdn.net/youngqj/article/details/8266177 1.首先安装完毕redis 2.安装boost 库 3.开发包下载地址: redis-cplusplus-client 4.上代码 #...
  • zdy0_2004
  • zdy0_2004
  • 2015-02-03 02:36
  • 1269

Redis java封装l类

public class RedisFacade { private static final Logger log = Logger.getLogger(RedisFacade.class); /** * Redis池映射hash表 */ private static final Conc...
  • Coolyqq
  • Coolyqq
  • 2016-03-16 12:46
  • 1757

redis的PHP封装

class MyRedis { private $redis; /** * @param string $host * @param int $post */ public function __construct($host = '...
  • gsls181711
  • gsls181711
  • 2015-07-28 18:39
  • 600

java对Redis 封装

java对Redis 封装最近公司用到redis , 参考了一些帖子以及github上的代码 ,自己整理出的一些简单的封装,如果有更好的想法,希望大家互相交流,谢谢!源文件目录有redis.properties 文件#最大分配的对象数 redis.pool.maxTotal=1024 #最大能够...
  • wanglei506
  • wanglei506
  • 2015-08-13 11:36
  • 3124
    个人资料
    • 访问:1366730次
    • 积分:12942
    • 等级:
    • 排名:第1255名
    • 原创:269篇
    • 转载:0篇
    • 译文:2篇
    • 评论:306条
    博主介绍
      Apache Hadoop Committer,其中主要专注于HDFS模块。毕业于HDU计算机系,研究领域分布式存储。曾就职于国内女性电商平台蘑菇街,目前就职于唯品会上海研发中心,数据平台与应用部门。
    新书发布
      新书<<深度剖析Hadoop HDFS>>发布上市,此书源自于笔者博客,重新经过整理,完善而成,此书的定位并不是一本纯源码分析的书籍,其中有许多笔者在工作和学习中对于HDFS的一些有趣的看法和理解。 链接:
    博客专栏
    最新评论