scoket 的方式进程间通信就是我们常用的网络通信和本地 Unix domain socket 通信,支持丰富的连接方式、通信协议等,这里对网络通信不深入描述,只介绍 Unix domain socket 概念和用法。
概念
Socket,又称套接字,是Linux跨进程通信(IPC,Inter Process Communication,详情参考:Linux进程间通信方式总结)方式的一种。相比于其他IPC方式,Socket更牛的地方在于,它不仅仅可以做到同一台主机内跨进程通信,它还可以做到不同主机间的跨进程通信。根据通信域的不同可以划分成2种:Unix domain socket 和 Internet domain socket。
- Internet domain socket用于实现不同主机上的进程间通信,大部分情况下我们所说的socket都是指internet domain socket。”IP+端口+协议” 的组合就可以唯一标识网络中一台主机上的一个进程
- Unix domain socket 又叫 IPC(inter-process communication 进程间通信) socket,用于实现同一主机上的进程间通信。虽然网络 socket 也可用于同一台主机的进程间通讯(通过 loopback 地址 127.0.0.1),但是 UNIX domain socket 用于 IPC 更有效率:不需要经过网络协议栈,不需要打包拆包、计算校验和、维护序号和应答等,只是将应用层数据从一个进程拷贝到另一个进程。这是因为,IPC 机制本质上是可靠的通讯,而网络协议是为不可靠的通讯设计的。
相关函数
1 | #include <sys/socket.h> |
使用 UNIX domain socket 的过程和网络 socket 十分相似,也要先调用 socket() 创建一个 socket 文件描述符。
family 指定为 AF_UNIX,使用 AF_UNIX 会在系统上创建一个 socket 文件,不同进程通过读写这个文件来实现通信。
type 可以选择 SOCK_DGRAM 或 SOCK_STREAM。SOCK_STREAM 意味着会提供按顺序的、可靠、双向、面向连接的比特流。SOCK_DGRAM 意味着会提供定长的、不可靠、无连接的通信。
protocol 参数指定为 0 即可。
1 | int bind(int sockfd, const struct sockaddr *addr, |
UNIX domain socket 与网络 socket 编程最明显的不同在于地址格式不同,用结构体 sockaddr_un 表示,网络编程的 socket 地址是 IP 地址加端口号,而 UNIX domain socket 的地址是一个 socket 类型的文件在文件系统中的路径,这个 socket 文件由 bind() 调用创建,如果调用 bind() 时该文件已存在,则 bind() 错误返回。因此,一般在调用 bind() 前会检查 socket 文件是否存在,如果存在就删除掉。
1 | int listen(int sockfd, int backlog); |
在 bind 之后要 listen,表示通过 bind 的地址(也就是 socket 文件)提供服务。
1 | int accept(int sockfd, struct sockaddr *_Nullable restrict addr, |
接下来必须用 accept() 函数初始化连接。accept() 为每个连接创立新的套接字并从监听队列中移除这个连接。
示例代码
server 端
1 | #include <stdio.h> |
SOCKET_NAME 是 Unix Domain Socket 的文件路径。它可以是任意有效的文件路径,但是需要注意以下几点:
- 路径应该是可访问的,以便客户端和服务端都能找到它。
- 如果路径所在的目录不存在,会导致创建失败。
- 如果路径已经被其他进程使用,可能会导致冲突。
- 在程序结束时,通常需要删除这个文件,以免占用系统资源。
- 通常,Unix Domain Socket 文件路径会放在 /tmp 或 /var/run 目录下,以便于管理
客户端
1 | #include <stdio.h> |
运行结果:
参考文档:
- https://man7.org/linux/man-pages/man7/socket.7.html
- https://man7.org/linux/man-pages/man7/unix.7.html
- https://www.cnblogs.com/sparkdev/p/8359028.html
- https://zhuanlan.zhihu.com/p/234806787
本文链接:https://www.zoucz.com/blog/2022/07/25/fcdb59d0-a2dd-11ee-bb9f-1566042b6386/