多进程/多线程并发编程

Unix Domain Socket 编程:字节流与数据报套接字详解

Unix Domain Socket 编程:字节流与数据报套接字详解


一、字节流套接字(SOCK_STREAM

1. 核心特性

可靠传输:提供类似 TCP 的有序、无丢失数据流,无记录边界。
全双工通信:支持双向数据传输,需通过 listen()/accept() 建立连接。
适用场景:需高可靠性的连续数据交互(如文件传输、RPC 服务)。

2. 核心系统调用

(1)socket() 创建套接字

int socket(int domain, int type, int protocol);

参数
domain:必须为 AF_UNIXAF_LOCAL
type:设为 SOCK_STREAM
protocol:固定为 0
返回值:成功返回文件描述符,失败返回 -1(如 EPROTONOSUPPORT 协议不支持)。

(2)bind() 绑定地址

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

地址结构

struct sockaddr_un {
    sa_family_t sun_family;    // AF_UNIX
    char sun_path[108];        // 文件路径或抽象名称
};

路径类型
普通路径:如 /tmp/mysocket.sock,需确保路径可写且无冲突。
抽象命名空间(Linux 特有):sun_path[0] = '\0',后续字符为抽象名(无需文件实体)。
addrlen 计算offsetof(struct sockaddr_un, sun_path) + strlen(name)(抽象名需 +1)。

(3)listen() 监听队列

int listen(int sockfd, int backlog);

backlog:最大等待连接数,建议设为 SOMAXCONN
错误处理:若队列满,后续连接请求直接返回 ECONNREFUSED

(4)accept() 接收连接

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

addr 参数:通常设为 NULL(客户端地址无意义)。
返回值:新套接字描述符专用于该连接。

(5)数据传输

ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);

flags 标志
MSG_OOB:带外数据(需双方支持)。
MSG_DONTWAIT:非阻塞模式。


二、数据报套接字(SOCK_DGRAM

1. 核心特性

保留消息边界:每次 send() 对应一次 recv(),数据按报文独立接收。
无连接特性:无需建立连接,可直接发送数据。
可靠性:数据不丢失但无序(与 UDP 不同,Unix 域数据报本身可靠)。
适用场景:日志传输、实时状态广播等低延迟场景。

2. 核心系统调用

(1)socket() 创建套接字

int socket(int domain, int type, int protocol);

type:设为 SOCK_DGRAM

(2)bind() 绑定地址

地址规则:同字节流套接字,但允许同一地址被多次绑定(需设置 SO_REUSEADDR)。

(3)直接数据收发

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
               const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                 struct sockaddr *src_addr, socklen_t *addrlen);

dest_addr:目标地址(必须已绑定)。
src_addr:接收时可获取发送方地址。

(4)连接模式(可选)

int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

作用:绑定默认目标地址,后续可使用 send()/recv()以及write()/read()


三、Linux 抽象 Socket 名空间(跨进程通用)

1. 实现方式

命名规则sun_path[0] = '\0',后续字符为抽象名(如 \0myapp)。
优势
• 无文件系统依赖,避免路径权限问题。
• 进程退出后自动释放,无需手动清理。

2. 系统查询

ss -x -a | grep '@'        # 查看活跃抽象套接字
cat /proc/net/unix         # 内核级列表(含 inode 和权限)

四、进阶功能对比

特性字节流套接字数据报套接字
连接管理listen()/accept()无连接
记录边界无边界(连续流)保留边界
最大消息长度无限制受限于内核缓冲区(通常 130KB)
描述符传递支持 (sendmsg())支持 (sendmsg())
凭证传递支持(SO_PASSCRED支持(SO_PASSCRED

五、总结

字节流套接字适用于需要可靠连续数据流的场景(如数据库连接),而数据报套接字更适合短消息、无连接交互。Linux 抽象命名空间通过消除文件依赖提升了安全性和便捷性,尤其在容器化环境中优势显著。开发者应根据业务需求选择通信模式,并注意两者的系统调用差异。

回复

This is just a placeholder img.