Linux IPC進程間通信(一):管道

系列文章:
Linux IPC進程間通信(一):管道
Linux IPC進程間通信(二):共享內存
Linux IPC進程間通信(三):信號量
Linux IPC進程間通信(四):消息隊列


前言

Linux進程間通信(IPC)的一個重要方法就是管道,在學習管道之前,要理解兩個概念

  • 半雙工(讀端與寫端必須固定)
  • 全雙工(讀端與寫端不固定)

不論是無名管道還是有名管道,都屬於半雙工管道,理解這一點非常重要。

一.標準管道流

  • FILE *popen(const char *__command, const char *__modes)
    command 代表shell指令
    modes 分爲 "r"讀 和 "w"寫
    具體功能和Linux命令中的管道基本相同
void test1()
{
    //讀
    FILE *fp = popen("cat /etc/profile", "r");
    char buf[1000] = {0};
    while (fread(buf, sizeof(char), sizeof(buf), fp))
        cout << buf;
    cout << endl;
    pclose(fp);

    //寫
    char buf2[] = {"aaa bbb ccc ddd eee fff ggg hhh"};
    FILE *fp2 = popen("wc -w", "w");
    fwrite(buf2, sizeof(char), sizeof(buf2), fp2);
    pclose(fp2);
}

二.無名管道

  • 只能在親緣進程之間使用
  • 爲半雙工管道(即只能一端讀,一端寫)
  • 無名管道是特殊的文件,只能存在於內存中

注意

  1. 無名管道中的 read 函數會進行阻塞。
  2. 因爲pipe()函數只能創建出半雙工管道,所以fds[0]只能讀,fds[1]只能寫;如果是socketpair()函數創建出的全雙工管道就沒有這個限制。

案例:創建一個無名管道 與 父子進程,進行父寫子讀

void test2()
{
    int fds[2] = {0};
    pipe(fds);//fds[0] = 3, fds[1] = 4;
    if (fork() == 0)
    {
        close(fds[1]);
        char buf[100] = {0};
        read(fds[0], buf, sizeof(buf));
        cout << "child process reading:" << buf << endl;
        close(fds[0]);
        exit(0);
    }
    close(fds[0]);
    char buf[100] = "Helloworld";
    write(fds[1], buf, strlen(buf));
    cout << "father process is writing" << endl;
    close(fds[1]);
    wait(NULL);
}

三.命名管道

命名管道比起無名管道,即便不是親屬進程也能夠進行進程間通信
另外,命名管道可以作爲文件存在。
需要使用 mkfifo 命令創建命名管道

命名管道:讀寫操作案例

分別創建好 讀端寫端 , 並設置退出機制

注意:如果沒有設置退出機制,那麼read端 將會默認一直在接收 0 個字符,讀端將會一直打印空字符串

寫端 (write.cpp)

int main()
{
    int fdw = open("pipe", O_WRONLY);
    ERROR_CHECK(fdw, -1 ,"open w");
    char buf[100] = {0};
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        read(0, buf, sizeof(buf));
        write(fdw, buf, strlen(buf) - 1);
    }
    return 0;
}

讀端(read.cpp):

int main()
{
    int fdr = open("pipe", O_RDONLY);
    ERROR_CHECK(fdr, -1, "open r");
    char buf[100] = {0};
    int ret;
    while (1)
    {
        memset(buf, 0, sizeof(buf));
        ret = read(fdr, buf, sizeof(buf));
        if (ret == 0)
        {
            cout << "byebye" << endl;
            break;
        }
        cout << "ret = " << ret << endl;
        cout << "buf = " << buf << endl;
    }
    return 0;
}

通過以上程序,可以實現一端寫,一段讀的案例。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章