Skip to content

Unix Domain Socket

1. 模块架构

1.1 功能概述

Unix Domain Socket 是本地进程间通信的高效方式,支持流和数据报两种模式。

1.2 关键源文件

文件作用
net/unix/af_unix.cUnix socket 实现
net/unix/garbage.cUnix socket 垃圾回收
include/net/af_unix.hUnix socket 定义

2. 核心数据结构

2.1 struct unix_sock

c
// include/net/af_unix.h:50
struct unix_sock {
    struct socket socket;
    struct unix_address *addr;
    struct path path;
    struct mutex lock;
    unsigned long flags;

    struct hlist_node link;
    struct socket *peer;

    struct list_head linklist;
    struct sk_buff_head receive_queue;
    struct sk_buff_head long_name;
};

2.2 struct unix_address

c
// include/net/af_unix.h:30
struct unix_address {
    atomic_t refcnt;
    int len;
    unsigned int hash;
    struct sockaddr_un name;
};

2.3 struct unix_proto_ops

c
// net/unix/af_unix.c:2500
static const struct proto_ops unix_stream_ops = {
    .family = PF_UNIX,
    .owner = THIS_MODULE,
    .release = unix_release,
    .bind = unix_bind,
    .connect = unix_stream_connect,
    .socketpair = unix_socketpair,
    .accept = unix_accept,
    .getname = unix_getname,
    .poll = unix_poll,
    .ioctl = unix_ioctl,
    .listen = unix_listen,
    .shutdown = unix_shutdown,
    .sendmsg = unix_stream_sendmsg,
    .recvmsg = unix_stream_recvmsg,
};

3. 地址

3.1 unix_bind()

c
// net/unix/af_unix.c:1600
static int unix_bind(struct socket *sock, struct sockaddr *uaddr,
                     int addr_len)
{
    struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
    struct unix_sock *u = unix_sk(sock);
    struct dentry *dentry;

    // 创建 socket 文件
    dentry = kern_path_create(AT_FDCWD, sunaddr->sun_path, &path, 0);
    if (IS_ERR(dentry))
        return PTR_ERR(dentry);

    // 绑定到路径
    u->path = path;
    u->addr = unix_addr(sunaddr->sun_path);

    return 0;
}

4. 连接

4.1 unix_stream_connect()

c
// net/unix/af_unix.c:1800
static int unix_stream_connect(struct socket *sock,
                               struct sockaddr *uaddr, int addr_len, int flags)
{
    struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr;
    struct socket *other;
    struct unix_sock *u, *other_u;

    // 查找目标 socket
    other = unix_find_other(sunaddr->sun_path);
    if (IS_ERR(other))
        return PTR_ERR(other);

    other_u = unix_sk(other);

    // 连接
    unix_state_lock(other);
    if (other_u->peer) {
        unix_state_unlock(other);
        return -ECONNREFUSED;
    }

    // 互相引用
    sock_hold(sock);
    other_u->peer = sock;
    u->peer = other;

    unix_state_unlock(other);
    return 0;
}

4.2 unix_accept()

c
// net/unix/af_unix.c:1700
static int unix_accept(struct socket *sock, struct socket *newsock, int flags)
{
    struct sock *sk = sock->sk;
    struct sk_buff *skb;

    unix_state_lock(sk);

    // 从队列取出
    skb = skb_dequeue(&unix_sk(sk)->receive_queue);
    if (!skb) {
        // 等待连接
        err = unix_wait_for_accept(sock, flags);
        skb = skb_dequeue(&unix_sk(sk)->receive_queue);
    }

    // 创建新 socket
    newsock->state = SS_CONNECTED;
    newsock->ops = sock->ops;

    unix_state_unlock(sk);
    return 0;
}

5. 发送/接收

5.1 unix_stream_sendmsg()

c
// net/unix/af_unix.c:2100
static int unix_stream_sendmsg(struct socket *sock,
                                struct msghdr *msg, size_t len)
{
    struct sock *sk = sock->sk;
    struct unix_sock *u = unix_sk(sk);
    struct sk_buff *skb;
    int err;

    // 创建 skb
    skb = sock_alloc_send_skb(sk, len + sizeof(struct unix_skb_parms),
                               msg->msg_flags & MSG_DONTWAIT, &err);

    // 复制数据
    err = memcpy_from_msg(skb_put(skb, len), msg, len);

    // 放入接收队列
    unix_state_lock_nested(u->peer);
    skb_queue_tail(&unix_sk(u->peer)->receive_queue, skb);
    unix_state_unlock(u->peer);

    // 唤醒等待者
    sk->sk_data_ready(sk);

    return len;
}

5.2 unix_stream_recvmsg()

c
// net/unix/af_unix.c:2200
static int unix_stream_recvmsg(struct socket *sock,
                                struct msghdr *msg, size_t size,
                                int flags)
{
    struct sock *sk = sock->sk;
    struct sk_buff *skb;

    // 从队列取出
    skb = skb_dequeue(&unix_sk(sk)->receive_queue);
    if (!skb) {
        if (flags & MSG_DONTWAIT)
            return -EAGAIN;
        // 等待数据
    }

    // 复制数据
    err = skb_copy_datagram_msg(skb, 0, msg, skb->len);

    // 释放 skb
    consume_skb(skb);

    return err;
}

6. 垃圾回收

6.1 unix_gc()

c
// net/unix/garbage.c:100
void unix_gc(void)
{
    struct unix_sock *u;
    struct hlist_node *p;
    unsigned int cycle = 0;

    // 遍历所有 Unix socket
    spin_lock(&unix_gc_lock);
    hlist_for_each_entry(u, p, &unix_sockets, link) {
        u->gc_flags |= UNIX_GC_CANDIDATE;
        u->gc_cycle = cycle;
    }

    // 标记不可达的对象
    // 清理循环引用
    spin_unlock(&unix_gc_lock);
}

7. 权限

7.1 SO_PEERCRED

c
// 获取对端进程凭证
struct ucred {
    pid_t pid;     // 进程 ID
    uid_t uid;     // 用户 ID
    gid_t gid;     // 组 ID
};

// 通过 getsockopt SO_PEERCRED 获取

基于 VitePress 构建