国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

匿名管道與命名管道

這篇具有很好參考價值的文章主要介紹了匿名管道與命名管道。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一,進程間通信

什么是進程間通信

??進程間通信就是讓兩個進程進行交流,但是我們知道進程具有獨立性,每個進程OS都會為其維護一個pcb,一個進程中的數(shù)據(jù)在另一個進程中是看不到的,那怎么實現(xiàn)進程間通信的呢?
??兩個進程要想通信,首先它們需要看到同一份資源,其實就是操作系統(tǒng)出面,為它們提供了一塊公共的資源,就是一段內(nèi)存,可能以文件的方式提供,也可能就是提供的原始的內(nèi)存塊。

進程間通信的目的

??數(shù)據(jù)傳輸 :一個進程需要將它的數(shù)據(jù)發(fā)送給另一個進程。
??資源共享 :多個進程之間共享同樣的資源。
??通知事件 :一個進程需要向另一個或一組進程發(fā)送消息,通知它(它們)發(fā)生了某種事件(如進程終止時要通知父進程)。
??進程控制 :有些進程希望完全控制另一個進程的執(zhí)行(如Debug進程),此時控制進程希望能夠攔截另一個進程的所有陷入和異常,并能夠及時知道它的狀態(tài)改變。

管道的概念

?? 管道是一種古老的進程間通信的方式,最早出現(xiàn)于Unix系統(tǒng)種。我們把一個進程連接到另一個進程的一個數(shù)據(jù)流稱為一個“管道”。
??當前使用過Linux操作系統(tǒng)的應該都使用過管道,例如,我們用兩個指令的組合來算出一個文本有多少行。

cat test.txt | wc -l

匿名管道與命名管道
??管道就是OS通過以文件的形式,給兩個進程創(chuàng)建一份共享資源。其實就是兩個進程公用一塊內(nèi)核緩沖區(qū),一個進程從里面讀取數(shù)據(jù)每一個進程往其中寫數(shù)據(jù),進而達到通信的效果。

二,匿名管道

匿名管道的創(chuàng)建

??首先介紹一個系統(tǒng)接口pipe

int pipe(int pipefd[2]);

這個系統(tǒng)調(diào)用的功能就是創(chuàng)建一個匿名管道,注意到它的參數(shù)是一個int類型的數(shù)組,數(shù)組有兩個元素,其實這是兩個輸出型參數(shù)pipefd[0] 是以讀方式打開管道文件返回的文件描述符,pipefd[1] 是以寫方式打開管道文件返回的文件描述符。
如果創(chuàng)建成功0會被返回,反之-1被返回。
??創(chuàng)建了匿名管道之后,再通過fork系統(tǒng)調(diào)用創(chuàng)建子進程,這樣子進程就會繼承來自父進程的文件描述符表,那么子進程也會看到這個管道文件,從而達到兩個進程看到同一份資源。對于一個進程來說只能從這一管道文件讀或者是寫,不能既讀又寫,所以我們創(chuàng)建子進程后要關(guān)閉父進程與子進程的多余的文件描述符。

匿名管道使用

一般步驟:
??使用pipe創(chuàng)建管道文件
??使用fork創(chuàng)建子進程
??父子進程關(guān)掉相應的文件描述符
??父子進程間實現(xiàn)通信
??通信結(jié)束后關(guān)掉文件描述符
??對于命名管道還要使用unlink將磁盤文件刪除

#include <iostream>
#include <unistd.h>
#include <cerrno>
#include <string>
#include <cstring>
#include <cassert>

int main()
{
    // 1.創(chuàng)建管道
    int pipe_fd[2] = {0};
    int res = pipe(pipe_fd);
    if (res < 0)
    {
        perror("pipe");
        exit(errno);
    }
    // 2.創(chuàng)建子進程
    pid_t id = fork();
    if (id < 0)
    {
        perror("fork");
        exit(errno);
    }
    if (id == 0) // child
    {
        // 3.關(guān)閉相應的fd
        close(pipe_fd[0]);
        int cnt = 0;
        std::string str = "我是子進程我正在向管道中寫";
        char buffer[1024] = {'\0'};
        while (true)
        {
            //char ch = 'Y';
            snprintf(buffer, sizeof(buffer), "cnt = %d,%s", cnt++, str.c_str());
            //std::cout << "子進程正在寫第" << cnt++ << "次" << std::endl;
            int n = write(pipe_fd[1], buffer, strlen(buffer));
            //t n = write(pipe_fd[1], &ch, 1);
            assert(n >= 0);
            (void)n;
            sleep(1);
        }
        //5.通信結(jié)束后關(guān)掉相應的文件描述符
        close(pipe_fd[1]);
        exit(0);
    }
    // parent
    //  3.關(guān)閉相應的fd
    close(pipe_fd[1]);
    //4.進程間通信
    char buffer[1024] = {'\0'};
    while (true)
    {
        int n = read(pipe_fd[0], buffer, sizeof(buffer) - 1);
        assert(n >= 0);
        (void)n;
        std::cout << "我是父進程,我從子進程中讀取的數(shù)據(jù)是: " << buffer << std::endl;
        //sleep(20);
        sleep(1);
    }
    //5.通信結(jié)束后關(guān)掉相應的文件描述符
    close(pipe_fd[0]);
    return 0;
}

這段代碼就是嚴格按照上面的五個步驟,其中由于管道是單項通信的,這段代碼中子進程保留了寫端,父進程保留了讀端。達到了父子進程間的數(shù)據(jù)傳輸。

匿名管道與命名管道

匿名管道的特性以及四種場景

特點:
??管道實現(xiàn)的是單向通信,具有半雙工的特點。
匿名管道與命名管道
??管道的本質(zhì)是文件,由于fd的聲明周期是隨進程的—>管道的聲明周期是隨進程的

管道文件是一個內(nèi)存級的緩沖區(qū),不會將數(shù)據(jù)刷新到磁盤上。其本質(zhì)就是在內(nèi)核中創(chuàng)建的struct file結(jié)構(gòu)體,以讀方式打開管道文件的進程將數(shù)據(jù)或者是命令寫入struct file中的內(nèi)核級緩沖區(qū),以讀方式打開管道文件的進程,從緩沖區(qū)中,將數(shù)據(jù)讀出去。每個文件都有預期對應的inode結(jié)構(gòu)體,而inode結(jié)構(gòu)體中有兩個計數(shù)器-i_count-i_link,這兩個分別是針對內(nèi)存上和磁盤上的,當有進程打開文件的時候i_count就會加1,而close的時候會減1,當減到0的時候在內(nèi)核中創(chuàng)建的struct file結(jié)構(gòu)體就會被OS回收掉,而i_link是指這個文件的連接數(shù),使用unlink函數(shù)或者指令可以使i_link這個計數(shù)器減1,同樣的在減到0的時候,這個文件就會被在磁盤上刪除。而對于匿名管道如果所有的進程都切斷了與struct file的關(guān)系,也就是i_count減為0,此時struct file會被OS回收,并且在磁盤上的inode結(jié)構(gòu)體等也會被刪除。

匿名管道與命名管道
??匿名管道通信通常是有血緣關(guān)系的進程間通信的,例如父子進程,兄弟進程等。

匿名管道之所以能夠通信就是因為,子進程繼承了父進程的文件描述表,從而看到了相同的struct file結(jié)構(gòu)體,進而能夠進行進程間的通信,那么爺孫進程能夠通信嗎?答案是肯定的,父進程中的文件描述表繼承自它的父進程,子進程又繼承了父進程的文件描述符表,所以爺孫進程是可以看到同一份資源的,進而爺孫進程間是可以通信的。
對于兄弟進程,由于兄弟進程都繼承了來自它們父進程的文件描述符表,所以它們同樣可以看大一份相同的資源,從而可以實現(xiàn)進程間的通信。

??在管道通信中,寫入的次數(shù)與讀取的次數(shù)不是嚴格匹配的,表現(xiàn)為字節(jié)流。
??管道具有一定的協(xié)同能力,能讓讀端與寫端按照一定的規(guī)則進程通信,是自帶同步機制的。

管道通信的四種場景
??如果讀端讀完了所有數(shù)據(jù),寫端沒有繼續(xù)寫,那么讀端只能等待。

就用上面那份代碼做一個實驗:上面的代碼中子進程是寫端父進程是讀端,我們讓子進程寫完一次數(shù)據(jù)后休眠十秒,這期間讓父進程一直從管道中讀取數(shù)據(jù)。

匿名管道與命名管道
匿名管道與命名管道

父進程每讀出一條數(shù)據(jù)夠要等上幾秒中才能從管道中讀取出下一條數(shù)據(jù),這就很好的驗證了,如果讀端將管道中的數(shù)據(jù)都讀取了出來,而寫端并沒有寫入,這一期間讀端會一直等待。

??如果讀端不讀寫端一直寫入,那么將管道寫滿后就不能再寫入了。

讓子進程每次寫入一個字節(jié)的數(shù)據(jù),而父進程休眠上30秒,在這期間已經(jīng)足夠讓子進程把管道寫滿,同時還可以在子進程寫入時記錄一下次數(shù)。

匿名管道與命名管道

可以看到,子進程寫入了65000多次的時候,就不能再寫入了說明此時管道已經(jīng)被寫滿了,同時也從側(cè)面證明了管道的大小大約是4KB。

??如果關(guān)閉了寫端,讀取完畢管道數(shù)據(jù),再讀就會返回0,表面那個讀到了文件結(jié)尾。
匿名管道與命名管道
匿名管道與命名管道

可以看到,殺死寫端的子進程后,父進程在讀取的完管道中的數(shù)據(jù)后,read的返回值變?yōu)?,并且重復讀到的都是管道中最后的那條數(shù)據(jù)。

??如果寫端一直寫,讀端關(guān)閉,那么寫端的進程就會被OS殺死,因為OS不會維護沒有意義,低效率或者是浪費資源的事情。簡單說就是如果讀端關(guān)閉那么OS會殺死寫端的進程。

如果匿名管道的讀端關(guān)閉,那么OS會給寫端的進程發(fā)送SIGPIPE這個信號殺死寫端進程,為了驗證這一結(jié)論,父進程讀取一條數(shù)據(jù)后休眠10秒休眠后close掉讀端的fd,然后waitpid等待子進程讀取子進程獲取到的信號。

while (true)
    {
        int n = read(pipe_fd[0], buffer, sizeof(buffer) - 1);
        assert(n >= 0);
        (void)n;
        std::cout << "read的返回值:" << n << "我是父進程,我從子進程中讀取的數(shù)據(jù)是: " << buffer << std::endl;
        sleep(10);
        break;
        //sleep(1);
    }
    //5.通信結(jié)束后關(guān)掉相應的文件描述符
    close(pipe_fd[0]);
    int status = 0;
    waitpid(id,&status,0);
    std::cout << "singal : " << (status & 0x7f) << std::endl;

匿名管道與命名管道
匿名管道與命名管道

當讀端關(guān)閉后,OS會給寫端的進程發(fā)送13號SIGPIPE信號殺死該進程。

匿名管道的原理

??匿名管道就是一塊內(nèi)核緩沖區(qū)(在struct file內(nèi))。
??并且匿名管道文件對應的struct file是不會進行刷盤操作。

進程間通信就是要讓不同的進程看到相同的資源,而使用匿名管道這種通信方式,是子進程繼承了來自父進程的文件描述符表,從而和父進程看到了同一塊資源,達到進程間通信的效果。

匿名管道與命名管道

通過匿名管道實現(xiàn)簡易進程池。

??讓父進程通過fork系統(tǒng)調(diào)用創(chuàng)建多個子進程,并且父進程與每個子進程間都會通過匿名管道來進行進程間通信,通過匿名管道父進程給子進程發(fā)配任務信號,從而使子進程完成相應的任務。
匿名管道與命名管道
步驟:
??首先循環(huán)創(chuàng)建出多個匿名管道和多個子進程
??將每個子進程與某個匿名管道建立起聯(lián)系
??父進程關(guān)閉相應讀端,子進程關(guān)閉相應寫端
??通過進程間通信達到父進程對子進程的控制
??使用結(jié)束后關(guān)閉相應的文件描述符

在Task.hpp中創(chuàng)建相應的任務。

#pragma once
#include <iostream>
#include <vector>

#include <unistd.h>
typedef void (*func_t)();
void PrintLog()
{
    std::cout << " pid : " << getpid() << "打印日志任務,正在被執(zhí)行..." << std::endl;
}
void InsertMysql()
{
    std::cout << " pid : " << getpid() << "訪問數(shù)據(jù)庫任務,正在被執(zhí)行..." << std::endl;
}
void NetRequest()
{
    std::cout << " pid : " << getpid() << "訪問網(wǎng)絡的任務,正在被執(zhí)行..." << std::endl;
}
#define COMMAND_LOG 0
#define COMMAND_MYSQL 1
#define CONMAND_REQUEST 2
#define QUIT 3

class Task
{
public:
    Task()
    {
        functions.push_back(PrintLog);
        functions.push_back(InsertMysql);
        functions.push_back(NetRequest);
    }
    void Execute(int index)
    {
        functions[index]();
    }
    ~Task()
    {
    }

private:
    std::vector<func_t> functions;
};

在ctrlProcess.cpp中完成進程的控制

#include <iostream>
#include <unistd.h>
#include <cstdlib>
#include <cerrno>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/wait.h>
#include <cassert>
#include "Task.hpp"
const int num = 6;
Task t;
class EndPoint
{
public:
    int write_fd;
    pid_t child_pid;
    std::string _name;

public:
    EndPoint(int fd, pid_t id)
        : write_fd(fd), child_pid(id)
    {
        char namebuffer[64];
        snprintf(namebuffer, sizeof(namebuffer), "Process-%d[%d-%d]", number++, child_pid, write_fd);
        _name = namebuffer;
    }
    std::string getname() const
    {
        return _name;
    }
    std::string getname()
    {
        return _name;
    }
    ~EndPoint()
    {
    }

private:
    static int number;
};
int EndPoint::number = 1;
void WaitCommand()
{
    while (true)
    {
        int command = 0;
        int n = read(0, &command, sizeof(command));
        if (n > 0)
        {
            t.Execute(command);
        }
        else if (n == 0)
        {
            break;
        }
        else
        {
            break;
        }
        sleep(1);
    }
}
void CreateProcess(std::vector<EndPoint> &end_points)
{
    std::vector<int> close_array;
    for (int i = 0; i < num; ++i)
    {
        int pipe_fd[2] = {0};
        int n = pipe(pipe_fd);
        if (n < 0)
        {
            perror("pipe");
            exit(errno);
        }
        pid_t id = fork();
        if (id < 0)
        {
            perror("fork");
            exit(errno);
        }
        if (id == 0)
        {
            // 先關(guān)掉從父進程那里繼承得關(guān)于別的管道得寫端
            for (auto e : close_array)
            {
                close(e);
            }
            // child
            close(pipe_fd[1]);
            // 輸入重定向
            dup2(pipe_fd[0], 0);
            WaitCommand();
            close(pipe_fd[0]);
            exit(0);
        }
        // parent
        close(pipe_fd[0]);
        end_points.push_back(EndPoint(pipe_fd[1], id));
        close_array.push_back(pipe_fd[1]);
    }
}
int select_command()
{
    int command = 0;
    std::cout << "#############################" << std::endl;
    std::cout << "#0.PrintLog   #1.InsertMysql#" << std::endl;
    std::cout << "#2.NetRequest #3.Quit     ###" << std::endl;
    std::cout << "#############################" << std::endl;
    std::cout << "Please select# ";
    std::cin >> command;
    return command;
}
void MakeProcess(std::vector<EndPoint> &end_points)
{
    int cnt = 0;
    while (true)
    {
        // 1.選擇任務
        int command = select_command();
        if (command == 3)
            break;
        if (command < 0 || command > 2)
            continue;
        // 2.選擇進程---以輪詢的方式
        int index = cnt++;
        cnt %= end_points.size();
        std::cout << "父進程選擇了" << end_points[index].getname() << " 處理任務" << std::endl;
        // 3.下發(fā)任務
        write(end_points[index].write_fd, &command, sizeof(command));
        sleep(1);
    }
}
void RecycleProcess(std::vector<EndPoint> &end_points)
{
    // 依次關(guān)閉父進程的寫端,子進程就會退出
    for (int i = 0; i < end_points.size(); i++)
    {
        close(end_points[i].write_fd);
        int res = waitpid(end_points[i].child_pid, nullptr, 0);
        std::cout << "父進程回收了 " << end_points[i].child_pid << " 子進程" << std::endl;
        assert(res);
        (void)res;
        sleep(1);
    }
}
int main()
{
    srand((size_t)time(NULL));
    std::vector<EndPoint> end_points;
    CreateProcess(end_points);

    MakeProcess(end_points);

    RecycleProcess(end_points);
    
    return 0;
}

注意一個小問題,我在代碼中,沒fork出一個子進程后,都要先關(guān)掉它從父進程中繼承的多余的文件描述符,如果不這樣做那么會在你關(guān)閉父進程寫端的時候會出現(xiàn)bug。下面來解釋一下:

匿名管道與命名管道

父進程在創(chuàng)建第一個子進程的時候,子進程1會繼承第一個管道的讀端和寫端,然后父進程關(guān)閉掉管道1的讀端,子進程1關(guān)掉管道1的寫端。但是父進程在創(chuàng)建第2個管道的時候,第二個子進程不僅會繼承了管道2的讀寫端,還會繼承了管道1的寫端,同樣子進程3會進程了管道1的寫端和管道2的寫端。這樣的話在想結(jié)束進程前,關(guān)閉父進程的寫端,使對應子進程對應得管道得寫端關(guān)閉那么子進程讀完管道內(nèi)得所有數(shù)據(jù)后就會退出,但是在父進程關(guān)閉管道1得寫端得時候,就會出現(xiàn)問題,不僅父進程是管道1得寫端,子進程2和子進程3都是父進程得寫端,導致waitpid這段代碼一直待等待子進程1的退出,而一直卡在這。

int res = waitpid(end_points[i].child_pid, nullptr, 0);

匿名管道與命名管道
??解決的方法就是在創(chuàng)建一個新的子進程的時候,首先關(guān)掉繼承自父進程關(guān)于其他管道的寫端的文件描述符,達到一個匿名管道文件的寫端只有父進程。

演示:
匿名管道與命名管道

選擇任務始于用戶交互式的,發(fā)配任務是讓子進程輪詢的去執(zhí)行內(nèi)務的。

三,命名管道

命名管道的創(chuàng)建

??由于匿名管道只支持有血緣關(guān)系的進程實現(xiàn)通信,難道兩個毫不相干的進程就無法實現(xiàn)通信嘛?答案是否定的,沒有血緣關(guān)系的兩個進程可以通過命名管道的方式實現(xiàn)進程間的通信。
??命名管道與匿名管道的區(qū)別就是命名管道有名字,可以被你看到,可以通過mkfifo指令創(chuàng)建一個命名管道。
匿名管道與命名管道

匿名管道與命名管道

值得注意的是即使你向管道文件中寫了數(shù)據(jù),你仍然會看到,管道文件的大小是0,這是因為命名管道文件在磁盤上沒有其對應的data block數(shù)據(jù)塊,意味著它里面的數(shù)據(jù)都是在內(nèi)存上的不會沖刷到磁盤上。

??使用mkfifo函數(shù)創(chuàng)建命名管道

int mkfifo(const char *pathname, mode_t mode);

第一個參數(shù)是命名管道的名字,第二個參數(shù)是創(chuàng)建命名管道的權(quán)限。如果創(chuàng)建成功返回0,否則返回-1。
注意: 第二個參數(shù)的權(quán)限是要與umask掩碼運算后得到最終的權(quán)限的。

匿名管道與命名管道

命名管道的使用

??首先創(chuàng)建出命名管道
??一個進程以讀方式打開該管道,另一個進程以寫方式打開該管道
??實現(xiàn)進程間通信
??通信結(jié)束后關(guān)閉相應的文件描述符
??在關(guān)閉文件描述符后使用unlink函數(shù)刪除管道文件(關(guān)閉文件描述符是讓其i_count計數(shù)器為0,使用unlink是讓其i_link計數(shù)器為0 ,是這個文件在磁盤上被刪除)

comm.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <cerrno>
#include <cstdlib>
#include <fcntl.h>
#include <curses.h>
#include <cstring>
using namespace std;
string file_name = "fifo";

server.cpp

#include "comm.hpp"
int main()
{
    // 1.創(chuàng)建命名管道
    int n = mkfifo(file_name.c_str(), 0664);
    if (n == -1)
    {
        cerr << errno << strerror(errno) << endl;
        return 1;
    }
    // 2.打開管道文件
    int res = open(file_name.c_str(), O_RDONLY);
    if (res == -1)
    {
        perror("open");
        return 2;
    }
    // 3.通信
    while (true)
    {
        char buffer[1024];
        int ret = read(res, buffer, sizeof(buffer) - 1);
        // int ret = read(res, &buffer[0], sizeof(char));
        if (ret > 0)
        {
            buffer[ret] = '\0';
            cout << buffer << endl;
            // fflush(stdout);
        }
        else if (ret == 0)
        {
            cout << "寫端關(guān)閉" << endl;
            break;
        }
        else
            break;
    }
    // 4.關(guān)閉命名管道
    close(res);
    unlink(file_name.c_str());
    return 0;
}

client.cpp

#include "comm.hpp"

int main()
{
    // 客戶端打卡命名管道文件
    int n = open(file_name.c_str(), O_WRONLY);
    if (n == -1)
    {
        perror("open");
        return 3;
    }

    //通信
    char buffer[1024];
    memset(buffer, '\0', sizeof(buffer));
    while (true)
    {
        cout << "請輸入# ";
        fgets(buffer, sizeof(buffer), stdin);
        buffer[strlen(buffer) - 1] = '\0';
        write(n, buffer, strlen(buffer));
        // system("stty raw");
        // int c = getchar();
        // system("stty -raw");
        // write(n, (char *)&c, sizeof(char));
    }
    // 關(guān)閉文件
    close(n);
    return 0;
}

匿名管道與命名管道

這段代碼實現(xiàn)了客戶端輸入消息,在服務端可以接收到消息。

命名管道實現(xiàn)簡易的進程池

大體的思想與匿名管道實現(xiàn)進程池的思想一致,就是在創(chuàng)建管道,和使不同的進程與管道建立聯(lián)系的方式不同。
首先在頭文件中定義了三個管道文件的名字,在主進程中首先創(chuàng)建這三個管道,并且以寫方式打開管道,在其他三個次進程中,都以讀方式打開相應的進程,例如Process1就打開1.pipe管道文件。通過主進程給此進程發(fā)送任務編號,次進程從管道中讀取到信息后,去執(zhí)行相應的任務。最后在主進程中關(guān)閉掉所有的寫端,則在次進程中對應的管道寫端關(guān)閉在其read完所有數(shù)據(jù)后就會退出,也會關(guān)閉掉相應的文件描述符,最終在主進程中使用unlink函數(shù)刪除掉所有的管道文件。

comm.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <vector>
#include <string>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdio>
using namespace std;

const int num = 6;
string S[num] =
    {
        "1.pipe",
        "2.pipe",
        "3.pipe"};
// vector<string> s(3);
// void init_s()
// {
//     s[0] = "1.pipe";
//     s[1] = "2.pipe";
//     s[2] = "3.pipe";
// }

typedef void (*func_t)();
void PrintLog()
{
    std::cout << " pid : " << getpid() << "打印日志任務,正在被執(zhí)行..." << std::endl;
}
void InsertMysql()
{
    std::cout << " pid : " << getpid() << "訪問數(shù)據(jù)庫任務,正在被執(zhí)行..." << std::endl;
}
void NetRequest()
{
    std::cout << " pid : " << getpid() << "訪問網(wǎng)絡的任務,正在被執(zhí)行..." << std::endl;
}
#define COMMAND_LOG 1
#define COMMAND_MYSQL 2
#define CONMAND_REQUEST 3
#define QUIT 0

class Task
{
public:
    Task()
    {
        functions.push_back(PrintLog);
        functions.push_back(InsertMysql);
        functions.push_back(NetRequest);
    }
    void Execute(int index)
    {
        functions[index]();
    }
    ~Task()
    {
    }

private:
    std::vector<func_t> functions;
};

ctrlProcess.cpp

#include "comm.hpp"
class EndPoint
{
public:
    EndPoint(int fd, string name)
        : _write_fd(fd), _pipename(name)
    {
    }

public:
    int _write_fd;
    string _pipename;
};

int select_command()
{
    int command = 0;
    std::cout << "#############################" << std::endl;
    std::cout << "#0.PrintLog   #1.InsertMysql#" << std::endl;
    std::cout << "#2.NetRequest #3.Quit     ###" << std::endl;
    std::cout << "#############################" << std::endl;
    std::cout << "Please select# ";
    std::cin >> command;
    return command;
}
int main()
{
    // 1.打開相應的管道。
    for (int i = 0; i < 3; i++)
    {
        int n = mkfifo(S[i].c_str(), 0664);
        if (n == -1)
        {
            perror("mkfifo");
            return 1;
        }
    }
    vector<EndPoint> end_points;
    // 2.打開相應文件
    for (int i = 0; i < 3; i++)
    {
        int n = open(S[i].c_str(), O_WRONLY);
        if (n == -1)
        {
            perror("open");
            return 1;
        }
        end_points.push_back(EndPoint(n, string(S[i])));
    }
    cout << "size:----------" << end_points.size() << endl;
    // 通信
    int cnt = 0;
    while (true)
    {
        // 1.選擇任務
        int command = select_command();
        if (command == 3)
            break;
        if (command < 0 || command > 2)
            continue;
        // 2.選擇進程
        int index = cnt++;
        // cnt %= end_points.size();
        cnt %= 3;

        // 3.下發(fā)任務
        write(end_points[index]._write_fd, &command, sizeof(int));
        sleep(1);
    }
    // 關(guān)閉
    for (int i = 0; i < end_points.size(); i++)
    {
        close(end_points[i]._write_fd);
    }
    // 刪除pipe文件
    for (int i = 0; i < end_points.size(); i++)
    {
        unlink(end_points[i]._pipename.c_str());
    }
    std::cout << "已經(jīng)徹底刪除了pipe文件" << std::endl;
    return 0;
}

Process1.cpp

#include "comm.hpp"
int main()
{
    Task t;
    // 打開管道文件
    int n = open(S[0].c_str(), O_RDONLY);
    if (n == -1)
    {
        perror("open");
        return 2;
    }
    // 讀取任務編號
    int command = 0;
    while (true)
    {
        int res = read(n, &command, sizeof(command));
        if (res > 0)
        {
            t.Execute(command);
        }
        else if (res == 0)
        {
            cout << "寫端關(guān)閉 " << endl;
            break;
        }
        else
            break;
    }
    close(n);
    return 0;
}

Process2.cpp

#include "comm.hpp"

int main()
{
    Task t;
    // 打開管道文件
    int n = open(S[1].c_str(), O_RDONLY);
    if (n == -1)
    {
        perror("open");
        return 3;
    }
    // 讀取任務編號
    int command = 0;
    while (true)
    {
        int res = read(n, &command, sizeof(command));
        if (res > 0)
        {
            t.Execute(command);
        }
        else if (res == 0)
        {
            cout << "寫端關(guān)閉 " << endl;
            break;
        }
        else
            break;
    }
    close(n);
    return 0;
}

Process3.cpp

#include "comm.hpp"

int main()
{
    Task t;
    // 打開管道文件
    int n = open(S[2].c_str(), O_RDONLY);
    if (n == -1)
    {
        perror("open");
        return 4;
    }
    // 讀取任務編號
    int command = 0;
    while (true)
    {
        int res = read(n, &command, sizeof(command));
        if (res > 0)
        {
            t.Execute(command);
        }
        else if (res == 0)
        {
            cout << "寫端關(guān)閉 " << endl;
            break;
        }
        else
            break;
    }
    close(n);
    return 0;
}

演示:
匿名管道與命名管道

管道總結(jié)

??管道應用的一個限制就是只能在具有共同祖先(具有親緣關(guān)系)的進程間通信。
??如果我們想在不相關(guān)的進程之間交換數(shù)據(jù),可以使用FIFO文件來做這項工作,它經(jīng)常被稱為命名管道。
??命名管道是一種特殊類型的文件。
??匿名管道由pipe函數(shù)創(chuàng)建并打開。
??命名管道由mkfifo函數(shù)創(chuàng)建,打開用open。
??FIFO(命名管道)與pipe(匿名管道)之間唯一的區(qū)別在它們創(chuàng)建與打開的方式不同,一但這些工作完成之后,它們具有相同的語義。文章來源地址http://www.zghlxwxcb.cn/news/detail-438707.html

到了這里,關(guān)于匿名管道與命名管道的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權(quán),不承擔相關(guān)法律責任。如若轉(zhuǎn)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經(jīng)查實,立即刪除!

領(lǐng)支付寶紅包贊助服務器費用

相關(guān)文章

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包