匿名管道和命名管道的概述理解和c++实现——进程间通信

匿名管道和命名管道的概述理解(笔记版)


匿名管道的c++实现:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <cstdlib>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <cassert>
#include <vector>
#include <unordered_map>
#include <fcntl.h>

using namespace std;

typedef void (*funcs)();

vector<funcs> functor;

// 调试信息
unordered_map<uint32_t, string> info;

void func1()
{
    cout << "这是一个处理日志的任务, 执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n"
         << endl;
}

void func2()
{
    cout << "这是一个备份数据的任务, 执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n"
         << endl;
}

void func3()
{
    cout << "这是一个网络连接的任务, 执行的进程 ID [" << getpid() << "]"
         << "执行时间是[" << time(nullptr) << "]\n"
         << endl;
}

void loadTask()
{
    info.insert(make_pair(functor.size(), "处理日志"));
    functor.push_back(func1);
    info.insert(make_pair(functor.size(), "备份数据"));
    functor.push_back(func2);
    info.insert(make_pair(functor.size(), "网路连接"));
    functor.push_back(func3);
}

//<子进程的pid,该子进程对应的写端>
typedef pair<uint32_t, uint32_t> elem;
int processNum = 5;

void work(int blocks)
{
    cout << "进程[" << getpid() << "]"
         << " 开始工作" << endl;
    while (true)
    {
        uint32_t operatorCode = 0;
        ssize_t s = read(blocks, &operatorCode, sizeof(uint32_t));
        if (s == 0)
            break;
        assert(s == sizeof(uint32_t));
        (void)s;
        if (operatorCode < functor.size())
            functor[operatorCode]();
    }
    cout << "进程[" << getpid() << "]"
         << " 结束工作" << endl;
}

void balanceSendTask(const vector<elem> &processFds)
{
    srand((long long)time(nullptr));
    while (true)
    {
        sleep(1);
        // 选择一个进程, 选择进程是随机的,没有压着一个进程给任务
        // 较为均匀的将任务给所有的子进程 --- 负载均衡
        uint32_t process = rand() % processFds.size();
        uint32_t task = rand() % functor.size();
        write(processFds[process].second, &task, sizeof(uint32_t));
        cout << "父进程指派任务->" << info[task] << "给进程: " << processFds[process].first << " 编号: " << process << endl;
    }
}

// 父进程控制一批子进程通信(进程池)
int main()
{
    info.insert(make_pair(functor.size(), "处理日志"));
    functor.push_back(func1);
    info.insert(make_pair(functor.size(), "备份数据"));
    functor.push_back(func2);
    info.insert(make_pair(functor.size(), "网路连接"));
    functor.push_back(func3);

    vector<elem> assignTask;
    // 循环创建子进程
    for (size_t i = 0; i < processNum; i++)
    {
        int pipefd[2] = {0};
        if (pipe(pipefd) < 0)
        {
            cerr << "pipe error" << endl;
            return 1;
        }
        pid_t id = fork();
        if (id < 0)
        {
            cerr << "fork error" << endl;
        }
        else if (id == 0)
        {
            close(pipefd[1]);
            work(pipefd[0]);
            close(pipefd[0]);
            exit(0);
        }
        else
        {
            close(pipefd[0]);
            elem e(id, pipefd[1]);
            assignTask.push_back(e);
        }
    }
    balanceSendTask(assignTask);
    for (size_t i = 0; i < processNum; i++)
    {
        int res = waitpid(assignTask[i].first, nullptr, 0);
        if (res)
        {
            cout << "wait " << assignTask[i].first << " success" << endl;
        }
    }

    return 0;
}

// 父进程控制子进程通信
// int main()
// {
//     info.insert(make_pair(functor.size(), "处理日志"));
//     functor.push_back(func1);
//     info.insert(make_pair(functor.size(), "备份数据"));
//     functor.push_back(func2);
//     info.insert(make_pair(functor.size(), "网路连接"));
//     functor.push_back(func3);

//     int pipefd[2] = {0};
//     if (pipe(pipefd) < 0)
//     {
//         cerr << "pipe error" << endl;
//         return 1;
//     }
//     pid_t id = fork();
//     if (id < 0)
//     {
//         cerr << "fork error" << endl;
//         return 2;
//     }
//     else if (id == 0)
//     {
//         close(pipefd[1]);
//         while (true)
//         {
//             uint32_t operatorTask = 0;
//             // 希望读取sizeof(operatorTask)个字符到operatorTask(void *__buf)中,实际读取s个字符,
//             ssize_t s = read(pipefd[0], &operatorTask, sizeof(uint32_t));
//             if (s == 0)
//             {
//                 cout << "父进程退出了,我也退出了" << endl;
//                 break;
//             }
//             assert(s == sizeof(uint32_t));
//             // assert断言 在debug模式是编译有效
//             // release模式,断言就没有了;
//             // 一旦断言没有了,s变量就是只被定义了,没有被使用。
//             // release模式中,可能会有warning
//             (void)s;
//             if (operatorTask < functor.size())
//             {
//                 functor[operatorTask]();
//             }
//             else
//             {
//                 cerr << "bug? operatorTask = " << operatorTask << endl;
//             }
//         }
//         close(pipefd[0]);
//         exit(0);
//     }
//     else
//     {
//         close(pipefd[0]);
//         srand((long long)time(nullptr));
//         int num = functor.size();
//         int cnt = 10;
//         while (cnt--)
//         {
//             uint32_t assignTask = rand() % num;
//             cout << "父进程指派的任务是:" << info[assignTask] << ",编号是:" << cnt << endl;
//             write(pipefd[1], &assignTask, sizeof(uint32_t));
//             sleep(1);
//         }
//         close(pipefd[1]);
//         pid_t res = waitpid(id, nullptr, 0);
//         if (res > 0)
//             cout << "wait success" << endl;
//     }

//     return 0;
// }

// pipe基本通信的过程
// int main()
// {
//     int pipe_fd[2] = {0};
//     if (pipe(pipe_fd) != 0)
//     {
//         cerr << "pipe error" << endl;
//         return 1;
//     }

//     pid_t pid = fork();
//     if (pid < 0)
//     {
//         cerr << "fork error" << endl;
//         return 2;
//     }
//     else if (pid == 0)
//     {
//         close(pipe_fd[1]);
//         char buffer[1024];
//         while (1)
//         {
//             memset(buffer, 0, sizeof(buffer));
//             ssize_t r = read(pipe_fd[0], buffer, sizeof(buffer) - 1);
//             if (r > 0)
//             {
//                 buffer[r] = '\0';
//                 cout << "子进程读取成功," << buffer << endl;
//             }
//             else if (r == 0)
//             {
//                 cout << "父进程写完了,子进程也退出了" << endl;
//                 break;
//             }
//         }
//         close(pipe_fd[0]);
//         exit(0);
//     }
//     else
//     {
//         close(pipe_fd[0]);
//         const char *meg = "你好子进程,我是父进程, 这次发送的信息编号是: ";
//         int cnt = 0;
//         while (cnt < 5)
//         {
//             char spearBuffer[1024];
//             sprintf(spearBuffer, "%s %d", meg, cnt);
//             sleep(3);
//             write(pipe_fd[1], spearBuffer, sizeof(spearBuffer));
//             cnt++;
//         }
//         close(pipe_fd[1]);
//         cout << "父进程写完了" << endl;
//     }
//     pid_t res = waitpid(pid, 0, 1);
//     if (res > 0)
//     {
//         cout << "等待子进程成功" << endl;
//     }

//     return 0;
// }

命名管道的c++实现:

common.h头文件:

#pragma once

#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <cerrno>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

#define IPC_PATH "./.fifo"

serverFifo.cpp:

// 读取
#include "common.h"

using namespace std;

int main()
{
    umask(0);
    if (mkfifo(IPC_PATH, 0600) != 0)
    {
        cerr << "mkfifo error" << endl;
        return 1;
    }

    int pipeFd = open(IPC_PATH, O_RDONLY);
    if (pipeFd < 0)
    {
        cerr << "open fifo error" << endl;
        return 2;
    }

#define NUM 1024
    // 正常的通信过程
    char buffer[NUM];
    while (true)
    {
        ssize_t s = read(pipeFd, buffer, sizeof(buffer) - 1);
        if (s > 0)
        {
            buffer[s] = '\0';
            cout << "客户端->服务器# " << buffer << endl;
        }
        else if (s == 0)
        {
            cout << "客户退出啦,我也退出把";
            break;
        }
        else
        {
            // do nothing
            cout << "read: " << strerror(errno) << endl;
            break;
        }
    }

    close(pipeFd);
    cout << "服务端退出啦" << endl;
    unlink(IPC_PATH);
    return 0;
}

clientFifo.cpp:

// 写入
#include "common.h"

using namespace std;

int main()
{
    int pipeFd = open(IPC_PATH, O_WRONLY);
    if (pipeFd < 0)
    {
        cerr << "open: " << strerror(errno) << endl;
        return 1;
    }

#define NUM 1024
    char line[NUM];
    while (true)
    {
        printf("请输入你的消息# ");
        fflush(stdout);
        memset(line, 0, sizeof(line));
        // fgets -> C -> line结尾自动添加\0
        if (fgets(line, sizeof(line), stdin) != nullptr)
        {
            // abcd\n\0
            line[strlen(line) - 1] = '\0';
            write(pipeFd, line, strlen(line));
        }
        else
        {
            break;
        }
    }
    close(pipeFd);
    cout << "客户端退出啦" << endl;
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值