当前位置: 首页 > news >正文

c++实现在同一台主机两个程序实现实时通信

c++代码实现同一台主机两个程序实现实时通信

对于进程间通信方式有很多种,对于本机两个程序中可以实时通信那么应该选择哪个呢?很多人最快想到的就是socket通信。

套接字适用于跨网络的进程间通信,具有网络透明性、灵活性和安全性高的优点,但性能开销较大,延迟较高!

共享内存适用于同一台机器上的进程间通信,具有高性能、低延迟和高吞吐量的优点,但需要手动管理同步机制,安全性较低。所以我们优先使用共享内存来实现,在智能驾驶等工业场景中使用非常多。

共享内存实现

进程A:

#include <cstring>
#include <iostream>
#include <sys/shm.h>
#include <thread>
#include <unistd.h>

#define SHM_KEY_A 12345
#define SHM_KEY_B 67890
#define SHM_SIZE 1024

void send_messages(char* send_data)
{
    std::string message;
    while (std::getline(std::cin, message)) {
        if (message == "exit") {
            break;
        }

        strncpy(send_data, message.c_str(), SHM_SIZE - 1);
        send_data[SHM_SIZE - 1] = '\0';

        while (std::strlen(send_data) > 0) {
            usleep(100000); // 等待 100 毫秒
        }
    }
}

void receive_messages(char* recv_data)
{
    while (true) {
        while (std::strlen(recv_data) == 0) {
            usleep(100000); // 等待 100 毫秒
        }

        std::cout << "Received message: " << recv_data << std::endl;

        std::memset(recv_data, 0, SHM_SIZE);
    }
}

int main()
{
    // 创建共享内存A(用于接收消息)
    int shmid_a = shmget(SHM_KEY_A, SHM_SIZE, 0666);
    if (shmid_a == -1) {
        std::cerr << "Failed to get shared memory A" << std::endl;
        return 1;
    }

    // 创建共享内存B(用于发送消息)
    int shmid_b = shmget(SHM_KEY_B, SHM_SIZE, 0666);
    if (shmid_b == -1) {
        std::cerr << "Failed to get shared memory B" << std::endl;
        return 1;
    }

    // 将共享内存连接到当前进程
    char* recv_data = (char*)shmat(shmid_a, nullptr, 0);
    char* send_data = (char*)shmat(shmid_b, nullptr, 0);

    if (recv_data == (char*)-1 || send_data == (char*)-1) {
        std::cerr << "Failed to attach shared memory" << std::endl;
        return 1;
    }

    std::thread sender(send_messages, send_data);
    std::thread receiver(receive_messages, recv_data);

    sender.join();
    receiver.join();

    // 清理共享内存
    shmdt(recv_data);
    shmdt(send_data);
    shmctl(shmid_a, IPC_RMID, nullptr);
    shmctl(shmid_b, IPC_RMID, nullptr);

    return 0;
}

进程B:

#include <cstring>
#include <iostream>
#include <sys/shm.h>
#include <thread>
#include <unistd.h>

#define SHM_KEY_A 12345
#define SHM_KEY_B 67890
#define SHM_SIZE 1024

void send_messages(char* send_data)
{
    std::string message;
    while (std::getline(std::cin, message)) {
        if (message == "exit") {
            break;
        }

        strncpy(send_data, message.c_str(), SHM_SIZE - 1);
        send_data[SHM_SIZE - 1] = '\0';

        while (std::strlen(send_data) > 0) {
            usleep(100000); // 等待 100 毫秒
        }
    }
}

void receive_messages(char* recv_data)
{
    while (true) {
        while (std::strlen(recv_data) == 0) {
            usleep(100000); // 等待 100 毫秒
        }

        std::cout << "Received message: " << recv_data << std::endl;

        std::memset(recv_data, 0, SHM_SIZE);
    }
}

int main()
{
    // 获取共享内存A(用于发送消息)
    int shmid_a = shmget(SHM_KEY_A, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid_a == -1) {
        std::cerr << "Failed to create shared memory A" << std::endl;
        return 1;
    }

    // 获取共享内存B(用于接收消息)
    int shmid_b = shmget(SHM_KEY_B, SHM_SIZE, IPC_CREAT | 0666);
    if (shmid_b == -1) {
        std::cerr << "Failed to create shared memory B" << std::endl;
        return 1;
    }

    // 将共享内存连接到当前进程
    char* send_data = (char*)shmat(shmid_a, nullptr, 0);
    char* recv_data = (char*)shmat(shmid_b, nullptr, 0);

    if (send_data == (char*)-1 || recv_data == (char*)-1) {
        std::cerr << "Failed to attach shared memory" << std::endl;
        return 1;
    }

    std::thread sender(send_messages, send_data);
    std::thread receiver(receive_messages, recv_data);

    sender.join();
    receiver.join();

    // 清理共享内存
    shmdt(send_data);
    shmdt(recv_data);
    shmctl(shmid_a, IPC_RMID, nullptr);
    shmctl(shmid_b, IPC_RMID, nullptr);

    return 0;
}

代码简洁比较容易。有些捞仔可能会问了,除了共享内存还有没有其它方式呢?有!当然有,只不过性能不如共享内存啦。

命名管道实现

进程A:

#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <thread>
#include <unistd.h>

#define PIPE_NAME_A "pipe_a"
#define PIPE_NAME_B "pipe_b"

void send_messages(const std::string& pipe_name)
{
    std::ofstream pipe(pipe_name);

    if (!pipe) {
        std::cerr << "Failed to open named pipe for writing" << std::endl;
        return;
    }

    std::cout << "Enter messages to send (type 'exit' to quit):" << std::endl;

    while (true) {
        std::string message;
        std::getline(std::cin, message);

        if (message == "exit") {
            break;
        }

        pipe << message << std::endl;
        pipe.flush();
    }
}

void receive_messages(const std::string& pipe_name)
{
    std::ifstream pipe(pipe_name);

    if (!pipe) {
        std::cerr << "Failed to open named pipe for reading" << std::endl;
        return;
    }

    std::cout << "Waiting for messages..." << std::endl;

    while (true) {
        std::string message;
        std::getline(pipe, message);

        // 处理程序在没有数据时不会频繁地检查管道,从而节省CPU资源,同时保持对新数据的响应
        if (pipe.eof()) {
            sleep(1);
            pipe.clear();
            pipe.seekg(0, std::ios::end);
        } else {
            std::cout << "Received message: " << message << std::endl;
        }
    }
}

int main()
{
    // 创建命名管道
    if (mkfifo(PIPE_NAME_A, 0666) == -1) {
        std::cerr << "Failed to create named pipe A" << std::endl;
        return 1;
    }

    if (mkfifo(PIPE_NAME_B, 0666) == -1) {
        std::cerr << "Failed to create named pipe B" << std::endl;
        return 1;
    }

    std::thread sender(send_messages, PIPE_NAME_A);
    std::thread receiver(receive_messages, PIPE_NAME_B);

    sender.join();
    receiver.join();

    return 0;
}

进程B:

#include <fstream>
#include <iostream>
#include <sys/stat.h>
#include <thread>
#include <unistd.h>

#define PIPE_NAME_A "pipe_a"
#define PIPE_NAME_B "pipe_b"

void send_messages(const std::string& pipe_name)
{
    std::ofstream pipe(pipe_name);

    if (!pipe) {
        std::cerr << "Failed to open named pipe for writing" << std::endl;
        return;
    }

    std::cout << "Enter messages to send (type 'exit' to quit):" << std::endl;

    while (true) {
        std::string message;
        std::getline(std::cin, message);

        if (message == "exit") {
            break;
        }

        pipe << message << std::endl;
        pipe.flush();
    }
}

void receive_messages(const std::string& pipe_name)
{
    std::ifstream pipe(pipe_name);

    if (!pipe) {
        std::cerr << "Failed to open named pipe for reading" << std::endl;
        return;
    }

    std::cout << "Waiting for messages..." << std::endl;

    while (true) {
        std::string message;
        std::getline(pipe, message);

        if (pipe.eof()) {
            sleep(1);
            pipe.clear();
            pipe.seekg(0, std::ios::end);
        } else {
            std::cout << "Received message: " << message << std::endl;
        }
    }
}

int main()
{
    std::thread sender(send_messages, PIPE_NAME_B);
    std::thread receiver(receive_messages, PIPE_NAME_A);

    sender.join();
    receiver.join();

    return 0;
}

相对于共享内存的优缺点:

优点

  • 简单易用:命名管道的实现相对简单,适合用于简单的进程间通信。

缺点

  1. 性能开销:命名管道的性能略低于共享内存,因为数据需要通过内核缓冲区传输。共享内存是所有进程间通信(IPC)机制中最快的,因为它不需要在进程之间复制数据。
  2. 单向通信:命名管道通常是单向的,需要两个管道实现双向通信。

还可以使用消息队列实现(本人使用的是wsl2,微软不支持,故没有代码)

相关文章:

  • 阿里推出全新推理模型(因果语言模型),仅1/20参数媲美DeepSeek R1
  • ABB 继电器和晶体管输出端子使用
  • 双指针算法
  • 介绍一个能支持高带宽的EDID编辑软件
  • SpringCloud系列教程(十三):Sentinel流量控制
  • python脚本py文件加密 pyarmor
  • Linux - 文件
  • 算法之 前缀和
  • 力扣132. 分割回文串 II
  • 传统工厂转型实录:1套WMS系统如何砍掉40%仓储成本
  • 信奥赛CSP-J复赛集训(DP专题)(16):P1203 [USACO1.1] 坏掉的项链 Broken Necklace
  • 【Qt QML】Loader动态加载组件
  • 【SegRNN 源码理解】图示理解 forward的过程
  • Kanna 与 Swift:结合使用提升网络请求效率
  • vue3,Element Plus中隐藏树el-tree滚动条
  • AIP-160 过滤
  • 采用OllamaSharp实现.NET快速对接deepseek实现聊天、模型管理、流式响应等功能
  • 统计作业提交情况python脚本
  • css错峰布局/瀑布流样式(类似于快手样式)
  • JVM参数调整
  • 一个商务宣传怎么做网站合适/中国网站排名前100
  • 做旅游网站平台合作入驻/微信营销工具
  • 怎么把网站管理系统/招聘网站排名
  • 网站建设与推广培训学校/登录百度账号
  • 投资公司的经营范围有哪些/seo模拟点击算法
  • 成都网站制作创新互联/网站媒体推广方案