进程间通信(IPC)的方法:UNIX域套接字

news2025/1/13 7:53:05

      UNIX域套接字(UNIX domain socket)为我们提供了一种在进程之间建立通信通道的便捷方法,具有许多有用的内置功能。它支持面向流(TCP)和面向数据报(UDP)协议作为TCP/IP互联网套接字。我们还可以在阻塞和非阻塞模式之间进行选择。
      首先需要创建套接字并在套接字函数中指定AF_UNIX作为域套接字。创建套接字后,必须使用绑定函数将套接字绑定到唯一的文件路径。与AF_INET域中的Internet套接字绑定到唯一的IP地址和端口号不同,UNIX域套接字绑定到文件路径。文件系统中创建的此文件,当程序关闭且不再需要该文件时,你必须手动将其删除。
      UNIX域套接字与server/client网络套接字通信没有太大不同,但它旨在供本地文件系统使用。server/client网络套接字介绍参考:https://blog.csdn.net/fengbingchun/article/details/107848160

      UNIX域套接字总结
      (1).同步;
      (2).极高的吞吐量;存储设备速度限制;
      (3).双向通信;
      (4).以线性方式读写;
      (5).自动内存管理。

      注:以上内容主要来自网络整理。

      测试代码如下:

#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>
#include <iostream>

int main()
{
    // reference: https://biendltb.github.io/tech/inter-process-communication-ipc-in-cpp/
    const char* server_sock_path = "/tmp/unix_sock.server";
    const char* client_sock_path = "/tmp/unix_sock.client";

    pid_t pid = fork(); // create two processes of client and server
    if (pid < 0) {
        fprintf(stderr, "fail to fork\n");
        return -1;
    }

    if (pid != 0) { // server process(parent process)
        auto server_sock = socket(AF_UNIX, SOCK_STREAM, 0); // open the server socket with the SOCK_STREAM type
        if (server_sock == -1) {
            fprintf(stderr, "SERVER: fail to socket: %s\n", strerror(errno));
            exit(1);
        }

        // bind to an address on file system
        // similar to other IPC methods, domain socket needs to bind to a file system, so that client know the address of the server to connect to
        struct sockaddr_un server_addr;
        memset(&server_addr, 0, sizeof(server_addr));
        server_addr.sun_family = AF_UNIX;
        strcpy(server_addr.sun_path, server_sock_path);
        
        unlink(server_sock_path); // unlink the file before bind, unless it can't bind: error info: Address already in use
        auto rc = bind(server_sock, (struct sockaddr *)&server_addr, sizeof(server_addr));
        if (rc == -1) {
            fprintf(stderr, "SERVER: fail to bind: %s\n", strerror(errno));
            exit(1);
        }

        // listen and accept client connection
        // set the server in the "listen" mode and maximum pending connected clients in queue
        rc = listen(server_sock, 10);
        if (rc == -1) {
            fprintf(stderr, "SERVER: fail to listen: %s\n", strerror(errno));
            exit(1);
        }

        fprintf(stdout, "SERVER: Socket listening...\n");
        struct sockaddr_un client_addr;
        auto len = sizeof(client_addr);
        int client_fd = accept(server_sock, (struct sockaddr *)&client_addr, (socklen_t*)&len);
        if (client_fd == -1) {
            fprintf(stderr, "SERVER: fail to accept: %s\n", strerror(errno));
            exit(1);
        }
        fprintf(stdout, "SERVER: Connected to client at: %s\n", client_addr.sun_path);
        fprintf(stdout, "SERVER: Wating for message...\n");

        const int buf_len = 256;
        char buf[buf_len];
        memset(buf, 0, buf_len);
        int byte_recv = recv(client_fd, buf, buf_len, 0);
        if (byte_recv == -1) {
            fprintf(stderr, "SERVER: fail to recv: %s\n", strerror(errno));
            exit(1);
        }
        else
            fprintf(stdout, "SERVER: Server received message: %s.\n", buf);

        fprintf(stdout, "SERVER: Respond to the client...\n");
        memset(buf, 0, buf_len);
        strcpy(buf, "hello from server");
        rc = send(client_fd, buf, buf_len, 0);
        if (rc == -1) {
            fprintf(stderr, "SERVER: fail to send:%s\n", strerror(errno));
            exit(1);
        }
        fprintf(stdout, "SERVER: Done!\n");

        close(server_sock);
        close(client_fd);
        remove(server_sock_path); // remove access to a file named

        int status;
        auto pid2 = wait(&status); // system call suspends execution of the calling thread until one of its children terminates
        fprintf(stdout, "process ID of the terminated child: %d\n", pid2);
        if (WIFEXITED(status)) { // returns true if the child terminated normally
            fprintf(stdout, "child process ended with: exit(%d)\n", WEXITSTATUS(status));
        }
        if (WIFSIGNALED(status)) { // returns true if the child process was terminated by a signal
            fprintf(stderr, "child process ended with: kill -%d\n", WTERMSIG(status));
        }
    }

    if (pid == 0) { // client process(child process)
        int client_sock = socket(AF_UNIX, SOCK_STREAM, 0);
        if (client_sock == -1) {
            fprintf(stderr, "CLIENT: fail to socket: %s\n", strerror(errno));
            exit(1);
        }

        // bind client to an address on file system
        // Note: this binding could be skip if we want only send data to server without receiving
        struct sockaddr_un client_addr;
        memset(&client_addr, 0, sizeof(client_addr));
        client_addr.sun_family = AF_UNIX;
        strcpy(client_addr.sun_path, client_sock_path);

        unlink (client_sock_path);
        auto rc = bind(client_sock, (struct sockaddr *)&client_addr, sizeof(client_addr));
        if (rc == -1) {
            fprintf(stderr, "CLIENT: fail to bind: %s\n", strerror(errno));
            exit(1);
        }

        // Set server address and connect to it
        struct sockaddr_un server_addr;
        server_addr.sun_family = AF_UNIX;
        strcpy(server_addr.sun_path, server_sock_path);
        rc = connect(client_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
        if (rc == -1) {
            fprintf(stderr, "CLIENT: fail to connect: %s\n", strerror(errno));
            exit(1);
        }
        fprintf(stdout, "CLIENT: Connected to server.\n");

        // Send message to server
        const int buf_len = 256;
        char buf[buf_len];
        memset(buf, 0, buf_len);
        strcpy(buf, "hello from client");
        rc = send(client_sock, buf, buf_len, 0);
        if (rc == -1) {
            fprintf(stderr, "CLIENT: fail to send: %s\n", strerror(errno));
            exit(1);
        }
        fprintf(stdout, "CLIENT: Sent a message to server.\n");

        fprintf(stdout, "CLIENT: Wait for respond from server...\n");
        memset(buf, 0, buf_len);
        rc = recv(client_sock, buf, buf_len, 0);
        if (rc == -1) {
            fprintf(stderr, "CLIENT: fail to recv: %s\n", strerror(errno));
            exit(1);
        }
        else
            fprintf(stdout, "CLIENT: Message received: %s\n", buf);

        fprintf(stdout, "CLIENT: Done!\n");

        close(client_sock);
        remove(client_sock_path);
        exit(0);
    }

    fprintf(stdout, "====== test finish ======\n");
    return 0;
}

      编译脚本build.sh如下:

#! /bin/bash

if [ -d build ]; then
    echo "build directory already exists, it does not need to be created again"
else
    mkdir -p build
fi

cd build
cmake ..
make

rc=$?
if [[ ${rc} != 0 ]];then
    echo "#### ERROR: please check ####"
    exit ${rc}
fi

echo "==== build finish ===="

      CMakeLists.txt内容如下:

cmake_minimum_required(VERSION 3.22)
project(samples_multi_process)

set(CMAKE_BUILD_TYPE Release) # only works under linux
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -O2 -std=c++17")

file(GLOB samples ${PROJECT_SOURCE_DIR}/test_*.cpp)
#message(STATUS "samples: ${samples}")

foreach(sample ${samples})
    string(REGEX MATCH "[^/]+$" name ${sample})
    string(REPLACE ".cpp" "" exec_name ${name})
    #message(STATUS "exec name: ${exec_name}")

    add_executable(${exec_name} ${sample})
    target_link_libraries(${exec_name} rt)
endforeach()

      执行结果如下所示:

      GitHub:https://github.com/fengbingchun/Linux_Code_Test

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1016847.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

express动态路由未能匹配造成的404问题

一个react项目打包以后&#xff0c;使用express跑起来&#xff0c;访问首页是可以的&#xff0c;但是只要访问产品详情页&#xff0c;就会白屏&#xff0c;浏览器开发者模式一看&#xff1a;原来是404错误&#xff1a; 看了一下代码和日志&#xff0c;应该是路由没有被匹配上&a…

基于Java+SpringBoot+Vue的大学生考勤系统的设计与实现(24届毕业生强烈推荐!逻辑通畅、功能完善、花里胡哨、老师喜欢)

大学生考勤系统 一、前言二、我的优势2.1 自己的网站2.2 自己的小程序&#xff08;小蔡coding&#xff09;2.3 有保障的售后2.4 福利 三、开发环境与技术3.1 MySQL数据库3.2 Vue前端技术3.3 Spring Boot框架3.4 微信小程序 四、功能设计4.1 主要功能描述 五、系统实现5.1 学生功…

IDEA连接数据库-MySql为例

1.找到Database 说明&#xff1a;找到Data Source下面的MySql 2.点击mysql 3.填写相关配置 说明&#xff1a;填写连接哪台服务器(这里是本机)&#xff0c;账号&#xff0c;密码&#xff0c;然后点击Test Connection 4.显示 说明&#xff1a;表示一共有7个&#xff0c;但是展…

AE-如何制作湖面水波纹波动的效果

目录 1.新建水面合成 2.新建纯色层命名为“分形杂色”&#xff0c;并添加“分形杂色”效果&#xff0c;设置相关参数 3.添加3D效果&#xff0c;并添加摄像机和空对象 4.新建中秋节合成&#xff0c;导入背景图&#xff0c;新建调整图层&#xff0c;并在调整图层上增加“焦散…

Acwing 830. 单调栈

Acwing 830. 单调栈 题目描述代码展示 题目描述 代码展示 #include <iostream>using namespace std;const int N 100010;int stk[N], tt;int main() {int n;cin >> n;while (n -- ){int x;scanf("%d", &x);while (tt && stk[tt] > x) t…

Python编辑器和Pycharm的傻瓜式安装部署

给我家憨憨写的python教程 有惊喜等你找噢 ——雁丘 Python解释器Pycharm的安装部署 关于本专栏一 Python编辑器1.1 使用命令提示符编写Python程序1.2 用记事本编写Python程序 二 Pycharm的安装三 Pycharm的部署四 Pycharm基础使用技巧4.1 修改主题颜色4.2 修改字体4.3 快速修…

淘宝开店装修教程 (2023新版)

一、下载千牛 1. 浏览器打开淘宝 https://www.taobao.com/ 2. 进入 - 千牛卖家中心 3. 进入 - 关于千牛 4. 下载千牛 5. 下载页面 6. 下载安装桌面 二、登录千牛 1. 登录页面 2. 进入 - 千牛工作台 三、pc店铺装修 1. 进入 - pc店铺 2. 进入 - 装修页面 3. 删除没用的模块 从…

Hexo在多台电脑上提交和更新

文章目录 1.博客搭建2.创建一个新文件夹new&#xff0c;用于上传hexo博客目录3.github上创建hexo分支并设置为默认分支创建hexo分支将hexo分支设置为默认分支 4.进入新建的文件夹中git clone&#xff0c;再上传相关文件至hexo分支1.clone下来的文件夹内应该有个.gitignore文件&…

uniapp实现大气质量指标图(app端小程序端均支持,app-nvue不支持画布)

效果图如下&#xff1a; 思路&#xff1a; 1.首先我想到的就是使用图标库echarts或ucharts&#xff0c;可是找了找没有找到类似的。 2.其次我就想用画布来实现这个效果&#xff0c;直接上手。&#xff08;app-vue和小程序均可以实现&#xff0c;但是在app-nvue页面不支持画布…

【Node.js】数据库配置与操作、Session实现原理、JWT实现原理:

文章目录 一、数据库配置与操作【1】 数据库的基本操作【2】 使用 mysql 模块操作 MySQL 数据库 二、Session实现原理【1】HTTP 协议的无状态性【2】Cookie【3】Session 的工作原理【3】在 Express 中使用 Session 认证 三、JWT实现原理【1】JWT 的工作原理【2】JWT 的组成部分…

金融风控建模常用指标介绍(WOE, IV, KS, PSI)

金融风控建模常用指标介绍&#xff08;WOE, IV, KS, PSI&#xff09; 近期在做金融风控相关项目&#xff0c;有必要把特征和模型的衡量指标总结下&#xff0c;以备不时之需。这次主要介绍4个指标&#xff08;WOE, IV, KS, PSI&#xff09;。 WOE&#xff08;Weight of Evidenc…

嵌入式学习笔记(28)按键和CPU的中断系统

按键的物理特性 (1)、平时没人按的时候&#xff0c;弹簧把按键按钮弹开。此时内部断开的。 (2)、有人按下的时候&#xff0c;手的力量克服弹簧的弹力&#xff0c;将按钮按下&#xff0c;此时内部保持接通&#xff08;闭合&#xff09;状态&#xff1b;如果手拿开&#xff0c;…

无涯教程-JavaScript - COS函数

描述 COS函数返回给定Angular的余弦值。 语法 COS (number)争论 Argument描述Required/OptionalNumber The angle in radians for which you want the cosine.Required Notes 如果Angular以度为单位,则将Angular乘以PI()/180或使用RADIANS函数将Angular转换为弧度 弧度(…

汉威科技亮相2023上海传感器展,智能传感新品引关注

作为全球三大传感器展之一的中国&#xff08;上海&#xff09;国际传感器技术与应用展览会&#xff0c;被誉为全球传感器行业发展的风向标&#xff0c;每届展会都会展出数以万计的行业尖端传感新技术和新产品。今年&#xff0c;第8届中国&#xff08;上海&#xff09;国际传感器…

强大的Druid

一 基本原理 一次数据库访问总共分几步&#xff1f;三步&#xff1a;第一步是创建一个连接&#xff1b;第二步是操作数据&#xff1b;第三步是释放连接。对于一个业务动作来说&#xff0c;我们并不关心第一步和第三步&#xff0c;我们真正关心的是第二步——操作数据。为了做一…

51单片机智能小车之蓝牙控制并测速小车、wife控制小车、4g控制小车、语音控制小车

目录 1. 蓝牙控制小车 2. 蓝牙控制并测速小车 3. wifi控制测速小车 4. 4g控制小车 5. 语音控制小车 1. 蓝牙控制小车 使用蓝牙模块&#xff0c;串口透传蓝牙模块&#xff0c;又叫做蓝牙串口模块 串口透传技术&#xff1a; 透传即透明传送&#xff0c;是指在数据的传输过…

想了解软件测试生命周期知识吗?

一、软件测试的目的 1.基于不同的立场&#xff0c;存在着两种完全不同的测试目的。 2.从用户的角度出发&#xff0c;普遍希望通过软件测试暴露软件中隐藏的错误和缺陷&#xff0c;以考虑是否可接受该产品。 3.从软件开发者的角度出发&#xff0c;则希望测试成为表明软件产品…

【Python保姆级教程】List容器

文章目录 前言一、列表是什么二、列表的定义2.1 有初始值2.2 空列表使用方括号创建空列表使用list()函数创建空列表 三、list列表常用操作3.1 添加元素3.2 删除元素3.3 修改元素3.4 列表长度 四、遍历操作4.1 使用for循环4.2 使用while循环和索引 总结 前言 Python是一种广泛使…

Python傅立叶变换

1. 什么是傅里叶变换&#xff1f; 在数学中&#xff0c;变换技术用于将函数映射到与其原始函数空间不同的函数空间。傅里叶变换时也是一种变换技术&#xff0c;它可以将函数从时域空间转换到频域空间。例如以音频波为例&#xff0c;傅里叶变换可以根据其音符的音量和频率来表示…

在项目中,关于前端实现数据可视化的技术选择

前言 在项目中&#xff0c;数据可视化以图表、报表类型为主。 需求背景 技术框架是Vue2.x版本&#xff0c;组件库是Ant Design of Vue能够支撑足够多的图表类型开发图表大小/位置能够随意变动图表样式需要支持丰富多样的用户配置强大、开放的图表语法支持复杂的数据可视化场景…