目录
1、认识域套接字
2、unix域套接字相关API及地址结构介绍
(1) 创建unix域套接字
(2) 填充地址结构 sockaddr_un
3、unix域套接字实现进程间通信(以UDP为例)
1、认识域套接字
和之前TCP / UDP 编程使用的套接字不同,域套接字常用于同一台主机上的两个进程之间的通信,如前后台进程之间的通信。其本质是让两个进程可以访问到同一个unix套接字文件,只不过这个套接字文件必须由OS系统创建的,而并非我们手动创建。
和其他进程间通信方式相比,unix域套接字使用更方便、效率更高。
- 易用性:消息队列 > unix域套接字 > 管道 > 共享内存(常常需要搭配信号量)
- 效率:共享内存 > unix域套接字 > 管道 > 消息队列
2、unix域套接字相关API及地址结构介绍
unix域套接字使用的API 和 inet 套接字是一样的,在使用unix套接字前,需要决定是使用UDP协议还是TCP协议,协议的不同,填入的参数也会不同。
(1) 创建unix域套接字
socket函数的声明如下:
第一个参数 domain:填写的是 AF_UNIX 或者 AF_LOCAL
第二个参数 type:套接字类型。数据报套接字(UDP) 填的是 SOCK_DGRAM;流式套接字(TCP) 填的是 SOCK_STREAM。
第三个参数 protocol:协议类型。一般填 0。
返回值:成功返回套接字文件描述符,失败返回 -1
// UDP协议
socket(AF_LOCAL, SOCK_DGRAM, 0);
// TCP协议
socket(AF_LOCAL, SOCK_STREAM, 0);
(2) 填充地址结构 sockaddr_un
我们在发送数据(send/sendto)和bind函数绑定地址的时候,都会需要填充地址结构,但是填充的不是IP地址,而是unix套接字文件所在路径。地址结构的定义如下:
#define UNIX_PATH_MAX 108 // 该值可能会随系统变化(98~108)
struct sockaddr_un {
sa_family_t sun_family; // AF_UNIX
char sun_path[UNIX_PATH_MAX]; // 套接字文件所在路径
// 该套接字文件不可手动创建,服务端在绑定的时候会自动创建
// 填写的路径必须是绝对路径
};
注意:套接字文件无需我们手动创建,服务端在绑定的时候会自动创建。填充地址结构的目的是告诉OS,我们希望把套接字文件放哪以及套接字文件叫啥。
// 1. bind函数会自动创建套接字文件,必须要保证套接字文件不存在
if(!access(UNIX_DOMAIN_FILE, F_OK)) {
unlink(UNIX_DOMAIN_FILE);
}
// 2. 填充sockaddr_un 地址结构
struct sockaddr_un sun;
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));
3、unix域套接字实现进程间通信(以UDP为例)
(1) 服务端
// 最好放在一个头文件里,客户端和服务端同时引入这个文件
#define UNIX_DOMAIN_FILE /tmp/unix_socket
int fd = -1;
// 1. 创建基于UDP的unix域套接字
if ((fd = socket (AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
perror ("socket");
exit (1);
}
// 2. 判断UNIX_DOMAIN_FILE所指向的文件是否存在,如果存在,则删除
if(!access(UNIX_DOMAIN_FILE, F_OK)) {
unlink(UNIX_DOMAIN_FILE);
}
// 3. 填充sockaddr_un 地址结构
struct sockaddr_un sun;
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));
// 4. 服务端绑定地址
if (bind (fd, (struct sockaddr*) &sun, sizeof(sun)) < 0) {
perror ("bind");
exit (1);
}
(2) 客户端
// 最好放在一个头文件里,客户端和服务端同时引入这个文件
#define UNIX_DOMAIN_FILE /tmp/unix_socket
int fd = -1;
// 1. 创建基于UDP的unix域套接字
if ((fd = socket (AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
perror ("socket");
exit (1);
}
// 2. 判断UNIX_DOMAIN_FILE所指向的文件是否存在,如果存在,则删除
if(!access(UNIX_DOMAIN_FILE, F_OK)) {
unlink(UNIX_DOMAIN_FILE);
}
// 3. 填充sockaddr_un 地址结构
struct sockaddr_un sun;
memset(&sun, 0, sizeof(sun));
sun.sun_family = AF_LOCAL;
strncpy(sun.sun_path, UNIX_DOMAIN_FILE, strlen(UNIX_DOMAIN_FILE));
// 4. 发送数据
std::string msg = "hello";
sendto(fd, msg.c_str(), msg.size(), 0 ,(struct sockaddr*)&sun, sizeof(sun));