unix 域套接字实现进程间通信

         目录

1、认识域套接字

2、unix域套接字相关API及地址结构介绍

(1) 创建unix域套接字

(2) 填充地址结构 sockaddr_un

3、unix域套接字实现进程间通信(以UDP为例)


1、认识域套接字

和之前TCP / UDP 编程使用的套接字不同,域套接字常用于同一台主机上的两个进程之间的通信,如前后台进程之间的通信。其本质是让两个进程可以访问到同一个unix套接字文件,只不过这个套接字文件必须由OS系统创建的,而并非我们手动创建。

unix 域套接字实现进程间通信_第1张图片

和其他进程间通信方式相比,unix域套接字使用更方便、效率更高。

  • 易用性:消息队列 > unix域套接字 > 管道 > 共享内存(常常需要搭配信号量)
  • 效率:共享内存 > unix域套接字 > 管道 > 消息队列

2、unix域套接字相关API及地址结构介绍

unix域套接字使用的API 和 inet 套接字是一样的,在使用unix套接字前,需要决定是使用UDP协议还是TCP协议,协议的不同,填入的参数也会不同。

(1) 创建unix域套接字

socket函数的声明如下:

unix 域套接字实现进程间通信_第2张图片

第一个参数 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));

你可能感兴趣的:(Linux,基础,linux)