欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 汽车 > 维修 > 后端C++: 主从反应堆 Unix Domain Sockets (UDS) 通讯方式示例

后端C++: 主从反应堆 Unix Domain Sockets (UDS) 通讯方式示例

2024/10/24 12:23:19 来源:https://blog.csdn.net/weixin_74239689/article/details/140989315  浏览:    关键词:后端C++: 主从反应堆 Unix Domain Sockets (UDS) 通讯方式示例

Unix Domain Sockets

这种方式是主从反应堆中,主反应堆和从反应堆两个进程通信方式的一种。

这种方式是一种在 Unix / Linux 操作系统上用于进程间通讯的机制。与传统的网络套接字(TCP/IP Sockets)不同,UDS 在同一台机器上进行通讯,不需要通过网络协议栈,因此具有更高的性能和更低的延迟。

特点

  • 优点:速度快,延迟低,因为它们不需要网络栈。

  • 缺点:只能在同一台机器上使用。

  • 适用场景:适用于同一台机器上的进程间通讯,且对性能要求较高的场景。

代码流程以及示例

最主要的一点是如何实现文件描述符的传递。

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <vector>#define UDS_PATH "/tmp/uds_socket"
#define MAX_EVENTS 10// 子进程需要做的任务
void child_process(int uds_socket) {// epoll的处理过程可以省略,我们主要看两个进程是如何实现文件描述符的传递的int epoll_fd = epoll_create1(0);if (epoll_fd == -1) {perror("epoll_create1");exit(EXIT_FAILURE);}struct epoll_event ev, events[MAX_EVENTS];while (true) {// 接收来自主进程的客户端套接字描述符int client_socket;struct msghdr msg = {0};struct cmsghdr *cmsg;char buf[CMSG_SPACE(sizeof(client_socket))];char dummy;struct iovec io = { .iov_base = &dummy, .iov_len = 1 };msg.msg_iov = &io;msg.msg_iovlen = 1;msg.msg_control = buf;msg.msg_controllen = sizeof(buf);if (recvmsg(uds_socket, &msg, 0) < 0) {perror("recvmsg");exit(EXIT_FAILURE);}cmsg = CMSG_FIRSTHDR(&msg);if (cmsg == NULL || cmsg->cmsg_len != CMSG_LEN(sizeof(client_socket))) {std::cerr << "Invalid cmsg received\n";exit(EXIT_FAILURE);}if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {std::cerr << "Invalid cmsg_level or cmsg_type\n";exit(EXIT_FAILURE);}client_socket = *((int *) CMSG_DATA(cmsg));// 将客户端套接字描述符添加到 epoll 实例中ev.events = EPOLLIN;ev.data.fd = client_socket;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_socket, &ev) == -1) {perror("epoll_ctl: client_socket");exit(EXIT_FAILURE);}// 等待事件int nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);if (nfds == -1) {perror("epoll_wait");exit(EXIT_FAILURE);}for (int n = 0; n < nfds; ++n) {if (events[n].events & EPOLLIN) {char buffer[512];ssize_t count = read(events[n].data.fd, buffer, sizeof(buffer));if (count == -1) {perror("read");exit(EXIT_FAILURE);} else if (count == 0) {// 客户端关闭连接close(events[n].data.fd);} else {// 处理读取到的数据std::cout << "Received data: " << buffer << std::endl;}}}}close(epoll_fd);
}int main() {// 创建 Unix Domain Socketint uds_socket = socket(AF_UNIX, SOCK_STREAM, 0);if (uds_socket == -1) {perror("socket");exit(EXIT_FAILURE);}struct sockaddr_un addr;addr.sun_family = AF_UNIX;strcpy(addr.sun_path, UDS_PATH);// 绑定 Unix Domain Socketif (bind(uds_socket, (struct sockaddr*)&addr, sizeof(addr)) == -1) {perror("bind");exit(EXIT_FAILURE);}// 监听 Unix Domain Socketif (listen(uds_socket, 5) == -1) {perror("listen");exit(EXIT_FAILURE);}// 创建子进程pid_t pid = fork();if (pid == -1) {perror("fork");exit(EXIT_FAILURE);}if (pid == 0) {// 子进程close(uds_socket);child_process(uds_socket);} else {// 主进程while (true) {// 接收客户端连接int client_socket = accept(uds_socket, NULL, NULL);if (client_socket == -1) {perror("accept");exit(EXIT_FAILURE);}// 发送客户端套接字描述符到子进程struct msghdr msg = {0};struct cmsghdr *cmsg;char buf[CMSG_SPACE(sizeof(client_socket))];char dummy = '\0';struct iovec io = { .iov_base = &dummy, .iov_len = 1 };msg.msg_iov = &io;msg.msg_iovlen = 1;msg.msg_control = buf;msg.msg_controllen = sizeof(buf);cmsg = CMSG_FIRSTHDR(&msg);cmsg->cmsg_level = SOL_SOCKET;cmsg->cmsg_type = SCM_RIGHTS;cmsg->cmsg_len = CMSG_LEN(sizeof(client_socket));*((int *) CMSG_DATA(cmsg)) = client_socket;if (sendmsg(uds_socket, &msg, 0) < 0) {perror("sendmsg");exit(EXIT_FAILURE);}close(client_socket);}}close(uds_socket);unlink(UDS_PATH);return 0;
}

其中的关键点如下:

  • Unix Domain Socket 的创建和绑定: 在主进程中创建 Unix Domain Socket,并绑定到指定路径,用于主从进程之间的通信。

  • 描述符传递: 使用 sendmsg 和 recvmsg 进行描述符的传递。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com