redis之unix域套接字应用

11 篇文章 0 订阅

        在redis源码的server.c文件中的initServer()方法中有这样一段代码:

/* Open the listening Unix domain socket. */
if (server.unixsocket != NULL) {
    unlink(server.unixsocket); /* don't care if this fails */
    server.sofd = anetUnixServer(server.neterr,server.unixsocket,
        server.unixsocketperm, server.tcp_backlog);
    if (server.sofd == ANET_ERR) {
        serverLog(LL_WARNING, "Opening Unix socket: %s", server.neterr);
        exit(1);
    }
    anetNonBlock(NULL,server.sofd);
}

        根据注释可以知道这段代码是要打开unix域套接字进行监听,但是打开之前做了一个判断,即server.unixsocket是否为null。这个值是什么意思呢?又是从哪来的呢?看配置文件redis.conf

# TCP listen() backlog.
#
# In high requests-per-second environments you need an high backlog in order
# to avoid slow clients connections issues. Note that the Linux kernel
# will silently truncate it to the value of /proc/sys/net/core/somaxconn so
# make sure to raise both the value of somaxconn and tcp_max_syn_backlog
# in order to get the desired effect.
tcp-backlog 511

# Unix socket.
#
# Specify the path for the Unix socket that will be used to listen for
# incoming connections. There is no default, so Redis will not listen
# on a unix socket when not specified.
#
unixsocket /tmp/redis.sock
unixsocketperm 700

        可以看到redis中的unix域套接字默认是不打开的,这里是取消注释将其打开了,并定义了参数unixsocketunixsocketperm。并截取了上面一部分配置tcp-backlog,这个参数之前在文章:套接字api值listen函数中着重提到过,这里后面也会用到。可见方法中的值是来自配置文件。如果配置文件中没打开,那么server.unixsocket值就是为null,也就不必打开unix域套接字进行监听了。

        继续看if()里面,调用了一个anetUnixServer()方法,三个参数都来自配置文件。

/**
 * path: socket文件配置路径,默认/tmp/redis.sock
 * perm: 文件访问权限,默认700
 * backlog: listen方法参数,默认511
 **/
int anetUnixServer(char *err, char *path, mode_t perm, int backlog)
{
    int s;
    struct sockaddr_un sa;

    if ((s = anetCreateSocket(err,AF_LOCAL)) == ANET_ERR)
        return ANET_ERR;

    memset(&sa,0,sizeof(sa));
    sa.sun_family = AF_LOCAL;
    strncpy(sa.sun_path,path,sizeof(sa.sun_path)-1);
    if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa),backlog) == ANET_ERR)
        return ANET_ERR;
    if (perm)
        chmod(sa.sun_path, perm);
    return s;
}

static int anetCreateSocket(char *err, int domain)
{
    int s;
    if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
        anetSetError(err, "creating socket: %s", strerror(errno));
        return ANET_ERR;
    }

    /* Make sure connection-intensive things like the redis benchmark
     * will be able to close/open sockets a zillion of times */
    if (anetSetReuseAddr(err,s) == ANET_ERR) {
        close(s);
        return ANET_ERR;
    }
    return s;
}

        看方法体发现这里并没有调用socketpair()方法创建一对unix域套接字,而是调用的anetCreateSocket()方法创建的,实际也就是socket()方法,只不过第一个参数是AF_LOCALAF_UNIX的别名),返回unix域套接字描述符并赋值给s。然而这时的unix域套接字是没有名字的,无关进程还不能使用。

        anetUnixServer()方法中还定义了一个struct sockaddr_un结构体,定义如下:

struct sockaddr_un {
    sa_family_t  sun_family;      //AF_UNIX
    char         sun_path[108];   //pathname
};

        该结构的sun_path成员保存一个地址,redis就将该结构体和之前生成的套接字描述符s一起传给anetListen()方法。

static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len, int backlog)
{
    if (bind(s,sa,len) == -1) {
        anetSetError(err, "bind: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }

    if (listen(s, backlog) == -1) {
        anetSetError(err, "listen: %s", strerror(errno));
        close(s);
        return ANET_ERR;
    }
    return ANET_OK;
}

        该方法中主要就是干了两件事,先调用bind()方法将创建的unix域套接字s绑到结构体包含的地址上,然后调用listen()方法开始监听。当启动redis服务时,就会用该路径名创建一个socket文件,也就是这里的/tmp/redis.sock文件。注意该文件无法打开,也不能由应用程序用于通信。

        至此,redis中的unix域套接字部分就介绍到这里,欢迎交流。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值