【Linux后端服务器开发】管道设计

这篇具有很好参考价值的文章主要介绍了【Linux后端服务器开发】管道设计。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

一、管道通信

二、匿名管道

1. 匿名管道通信

2. 匿名管道设计

三、命名管道

comm.hpp

client.cc

serve.cc


一、管道通信

进程通信

数据传输:一个进程需要将它的数据发送给另一个进程

资源共享:多个进程之间共享同样的资源

通知事件:一个进程向另一个(一组)进程发送信息,通知它们发生了某种事件

进程控制:一个进程完全控制另一个进程的执行,如debug

通信本质

OS直接或间接给通信双方提供内存空间

通信的进程双方,能够读取到一份公共资源

管道文件是内存级文件

管道创建

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

 

管道读写端

  • 如果管道没有了数据,读端在读,默认会阻塞等待正在读取的进程
  • 管道是固定大小的空间,写端写满的时候,会阻塞等待读端读取
  • 写端关闭,读端在读,则读端读完管道数据也关闭
  • 读端关闭,写端在写,OS终止写端

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

int main() 
{
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);

    cout << "fds[0]: " << fds[0] << endl;
    cout << "fds[1]: " << fds[1] << endl;

    return 0;
}

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

管道可用于父子、兄弟、祖孙进程之间通信

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

二、匿名管道

1. 匿名管道通信

#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;

int main() 
{
    // 1. 创建管道文件,打开读写端
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);

    // 2. fork()
    pid_t id = fork();
    if (id == 0) 
    {
        //子进程通信代码
        close(fds[0]);  //关闭读端
        const char* s = "我是子进程,我正在给你发消息";
        int cnt = 0;
        while (true) 
        {
            char buffer[1024];
            snprintf(buffer, sizeof(buffer), "child->parent say: %s[%d][%d]", s, cnt++, getpid());
            write(fds[1], buffer, strlen(buffer));
            sleep(1);
        }
        exit(0);
    }

    //父进程通信代码
    close(fds[1]);  //关闭写端
    while (true) 
    {
        char buffer[1024];
        ssize_t s = read(fds[0], buffer, sizeof(buffer) - 1);
        if (s > 0) 
            buffer[s] = 0;
        cout << "Get Message# " << getpid() << buffer  << " | my pid: " << getpid() << endl;
        //父进程没有sleep
    }
    n = waitpid(id, nullptr, 0);
    assert(n == id);

    return 0;
}

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

2. 匿名管道设计

  • 将任务存入存入任务表vector中,将子进程存入信息存入subs容器中
  • 父进程随机将任务码发给5个子进程,子进程读取任务码完成任务(父进程为写端,子进程为读端),若子进程未读取任务,则进行阻塞等待
  • 通过随机数分配任务给随机子进程,让子进程负载均衡

代码设计流程:

  1. 建立任务表,建立子进程及和子进程通信的信道
  2. 父进程控制子进程,进行任务分配
  3. 回收子进程信息
#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cassert>
#include <cstring>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <vector>
using namespace std;

#define MakeSeed() srand((unsigned int)time(nullptr) ^ getpid())
#define PROCESS_NUM 5
#define TASK_NUM 10

typedef void(*func_t)();

void DownLoad() 
{
    cout << getpid() << " DownLoad Task" << endl;
    sleep(1);
}

void IOTask() 
{
    cout << getpid() << " IO Task" << endl;
    sleep(1);
}

void FlushTask() 
{
    cout << getpid() << " Flush Task" << endl;
}

void LoadTaskFunc(vector<func_t>& funcMap) 
{
    funcMap.push_back(DownLoad);
    funcMap.push_back(IOTask);
    funcMap.push_back(FlushTask);
}

/

class subEp 
{
public:
    subEp(pid_t subID, int writeFd)
        : _subID(subID), _writeFd(writeFd) 
    {
        char nameBuffer[1024];
        snprintf(nameBuffer, sizeof(nameBuffer), "process-%d[pid(%d)-fd(%d)]", num++, subID, _writeFd);
        _name = nameBuffer;
    }

    static int num;
    string _name;
    pid_t _subID;
    int _writeFd;
};

int subEp::num = 0;

// 读取
int RecvTask(int readFd) 
{
    int code = 0;
    ssize_t s = read(readFd, &code, sizeof(code));
    if (s == sizeof(int)) 
        return code;
    else if (s <= 0) 
        return -1;
    else 
        return 0;
}

void CreateSubProcess(vector<subEp>& subs, vector<func_t>& funcMap) 
{
    vector<int> deleteFd;
    for (int i = 0; i < PROCESS_NUM; ++i) 
    {
        int fds[2];
        int n = pipe(fds);
        assert(n == 0);
        (void) n;

        pid_t id = fork();
        if (id == 0) 
        {
            //建立一对一管道
            for (int i = 0; i < deleteFd.size(); ++i) 
                close(deleteFd[i]);
            //子进程处理任务
            close(fds[1]);
            while (true) 
            {
                // 1. 获取任务码,如果没收到任务码,则阻塞等待
                int commandCode = RecvTask(fds[0]);
                // 2. 执行任务
                if (commandCode >= 0 && commandCode < funcMap.size()) 
                    funcMap[commandCode]();
                else 
                    break;
            }
            exit(0);
        }
        close(fds[0]);
        subEp sub(id, fds[1]);
        subs.push_back(sub);
        deleteFd.push_back(fds[1]);
    }
}

void SendTask(const subEp& process, int taskNum) 
{
    cout << "send task num " << taskNum << " to " << process._name << endl;
    int n = write(process._writeFd, &taskNum, sizeof(taskNum));
    assert(n == sizeof(int));
    (void)n;
}

void LoadBlanceContrl(const vector<subEp>& subs, vector<func_t>& funcMap, int count) 
{
    int procNum = subs.size();
    int taskNum = funcMap.size();
    while (count--) 
    {
        int subIDx = rand() % procNum;
        int taskIDx = rand() % taskNum;
        SendTask(subs[subIDx], taskIDx);
        sleep(1);
    }
    for (int i = 0; i < procNum; ++i) 
        close(subs[i]._writeFd);
}

void WaitProcess(vector<subEp>& subs) 
{
    int procNum = subs.size();
    for (int i = 0; i < procNum; ++i) 
    {
        waitpid(subs[i]._subID, nullptr, 0);
        cout << "wait sub process success ... " << subs[i]._subID << endl;
    }
}

int main() 
{
    MakeSeed();
    // 1. 建立子进程并建立和子进程通信的信道
    //    [子进程id,wfd]
    vector<func_t> funcMap;
    LoadTaskFunc(funcMap);
    vector<subEp> subs;
    CreateSubProcess(subs, funcMap);

    // 2. 父进程控制子进程
    LoadBlanceContrl(subs, funcMap, TASK_NUM);

    // 3. 回收子进程信息
    WaitProcess(subs);

    return 0;
}

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

三、命名管道

让不同进程打开指定名称(路径+文件名)的同一个文件

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道

comm.hpp

#pragma once

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

#define NAMED_PIPE "/root/test/pipe/named_pipe"

bool CreateFilo(const std::string& path) 
{
    umask(0);
    int n = mkfifo(path.c_str(), 0666);
    if (n == 0) 
    {
        return true;
    }
    else 
    {
        std::cout << "errno: " << errno << "err string: " << strerror(errno) << std::endl;
        return false;
    }
}

void RemoveFifo(const std::string& path) 
{
    int n = unlink(path.c_str());
    assert(n == 0);     //意料之中用assert判断,意料之外用 if else
    (void)n;
}

client.cc

#include "comm.hpp"

int main() 
{
    std::cout << "client begin" << std::endl;
    int wfd = open(NAMED_PIPE, O_WRONLY, 0666);
    std::cout << "client end" << std::endl;
    if (wfd < 0) 
        exit(1);

    //write
    char buffer[1024];
    while (true) 
    {
        std::cout << "please say# ";
        fgets(buffer, sizeof(buffer), stdin);
        if (strlen(buffer) > 0) 
            buffer[strlen(buffer) - 1] = 0;        
        ssize_t n = write(wfd, buffer, strlen(buffer));
        assert(n == strlen(buffer));
        (void)n;
    }

    close(wfd);
    return 0;
}

serve.cc

#include "comm.hpp"

int main() 
{
    bool r = CreateFilo(NAMED_PIPE);
    assert(r);
    (void)r;

    std::cout << "serve begin" << std::endl;
    int rfd = open(NAMED_PIPE, O_RDONLY);
    std::cout << "serve end" << std::endl;
    if (rfd < 0) 
        exit(1);

    //read
    char buffer[1024];
    while (true) 
    {
        ssize_t s = read(rfd, buffer, sizeof(buffer) - 1);
        if (s > 0) 
        {
            std::cout << "client->serve# " << buffer << std::endl;
        }
        else 
        {
            perror("read");
            exit(1);
        }
    }

    close(rfd);

    RemoveFifo(NAMED_PIPE);
    return 0;
}

【Linux后端服务器开发】管道设计,Linux后端服务器开发,服务器,linux,进程间通信,管道,命名管道,匿名管道文章来源地址https://www.toymoban.com/news/detail-547059.html

到了这里,关于【Linux后端服务器开发】管道设计的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【Linux后端服务器开发】封装线程池实现TCP多线程通信

    目录 一、线程池模块 Thread.h LockGuard.h ThreadPool.h 二、任务模块模块 Task.h 三、日志模块 Log.h 四、守护进程模块 Deamon.h  五、TCP通信模块 Server.h Client.h server.cpp client.cpp 关于TCP通信协议的封装,此篇博客有详述: 【Linux后端服务器开发】TCP通信设计_命运on-9的博客-CSDN博客 线程池

    2024年02月16日
    浏览(32)
  • 【Linux后端服务器开发】协议定制(序列化与反序列化)

    目录 一、应用层协议概述 二、序列化与反序列化 Protocal.h头文件 Server.h头文件 Client.h头文件 server.cpp源文件 client.cpp源文件 什么是应用层 ?我们通过编写程序解决一个个实际问题、满足我们日常需求的网络程序,都是应用层程序。 协议是一种“约定”,socket的api接口,在读

    2024年02月16日
    浏览(29)
  • 强推Linux高性能服务器编程, 真的是后端开发技术提升, 沉淀自身不容错过的一本经典书籍

    目录 第1章 TCP/IP协议 1.1 TCP/IP协议族体系结构以及主要协议 1.1.1 数据链路层 1.1.2 网络层 1.1.3 传输层 1.1.4 应用层 1.2 封装 1.3 分用 1.5 ARP协议工作原理 1.5.1 以太网ARP请求/应答报文详解 1.5.2 ARP高速缓存的查看和修改 1.5.3 使用tcpdump观察ARP通信过程所得结果如下 本篇核心关键所在

    2024年02月07日
    浏览(33)
  • 如何在linux服务器上用Nginx部署Vue项目,以及如何部署springboot后端项目

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 本文内容记录如何在Linux(Ubuntu)系统上安装Nginx,并部署打包好的Vue前端项目,最后通过浏览器访问。 提示:以下是本篇文章正文内容,下面案例可供参考

    2024年04月16日
    浏览(33)
  • 深度学习服务器(Linux)开发环境搭建教程

    当你拿到一台服务器的使用权时,最头疼的莫过于登陆服务区并配置开发环境。本文将从0开始,讲述一台刚申请的服务器远程登陆并配置开发环境的全过程。希望对你有所帮助 打开MobaXterm软件,创建一个新的Session,选择SSH登陆。其中Remote host填服务器的IP地址,Specify userna

    2024年02月05日
    浏览(38)
  • FTP服务器移植到Linux开发板

    提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档 提示:这里可以添加本文要记录的大概内容: 将Linux开发板作为一个小型的 FTP 服务器,这样就可以通过 FileZilla 软件直接在开发板和 windows 之间通过网络进行文件互传。在开发板上搭建 FTP 服务器很简单

    2024年02月14日
    浏览(27)
  • 使用pycharm远程连接到Linux服务器进行开发

    本地的 PyCharm 能达到和远程服务器之间的文件同步; 本地的 PyCharm 能够使用远程服务器的开发环境; PyCharm:PyCharm 2021.3 (Professional Edition) Linux服务器:Ubuntu20.04 配置项路径:Tools ,Deployment,Configuration 在 Connection 标签页中,点击【···】,对 SFTP 连接进行编辑。 Username:注

    2024年02月08日
    浏览(38)
  • 基于linux下的高并发服务器开发(第一章)- Linux系统IO函数

     (1)man 2 open 打开一个已经存在的文件 int open(const char *pathname, int flags); 参数:             pathname:要打开文件路径             - flags:对文件的操作权限设置还有其他的设置             O_RDONLY,O_WRONLY,O_RDWR 这三个设置是互斥的 返回值:             返回一个新的文件描述

    2024年02月16日
    浏览(42)
  • IntelliJ IDEA无公网远程Linux服务器环境开发(建议收藏!)

    IDEA的远程开发功能,可以将本地的编译、构建、调试、运行等工作都放在远程服务器上执行,而本地仅运行客户端软件进行常规的开发操作即可,旧版本IDEA目前不支持该功能.,本例使用的是IDEA2023.2.5版本 下面介绍如何在IDEA中设置远程连接服务器开发环境并结合Cpolar内网穿透工

    2024年02月05日
    浏览(34)
  • 「远程开发」VSCode使用SSH远程linux服务器 - 公网远程连接

    转发自cpolar内网穿透的文章:【Vscode远程开发】使用SSH远程连接服务器 「内网穿透」 远程连接服务器工具有很多,比如XShell、putty等,可以通过ssh来远程连接服务器,但这用于写代码并不方便,可能需要现在本地写好代码后再将源代码传送到服务器运行、服务器上的图片也无

    2024年02月06日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包