詳解linux進程間通信-管道 popen函數 dup2函數

来源:https://www.cnblogs.com/liudw-0215/archive/2018/04/26/8952609.html
-Advertisement-
Play Games

前言:進程之間交換信息的唯一方法是經由f o r k或e x e c傳送打開文件,或通過文件系統。本章將說明進程之間相互通信的其他技術—I P C(InterProcess Communication)。今天將介紹半雙工的管道。 一、匿名管道 1、匿名管道介紹: 管道有兩種限制; (1) 它們是半雙 ...


  前言:進程之間交換信息的唯一方法是經由f o r ke x e c傳送打開文件,或通過文件系統。本章將說明進程之間相互通信的其他技術—I P CInterProcess Communication)。今天將介紹半雙工的管道。

  一、匿名管道

  1、匿名管道介紹:

   管道有兩種限制;
  (1) 它們是半雙工的。數據只能在一個方向上流動。
  (2)
它們只能在具有公共祖先的進程之間使用。通常,一個管道由一個進程創建,然後該進程調用f o r k,此後父、子進程之間就可應用該管道。 

  管道是由調用p i p e函數而創建的:
  #include <unistd.h>
  int pipe(intf i l e d e s [ 2 ]) ;
  返回:若成功則為0,若出錯則為 - 1

  經由參數f i l e d e s返回兩個文件描述符: f i l e d e s [ 0 ]為讀而打開, f i l e d e s [ 1 ]為寫而打開。 f i l e d e s [ 1 ]
的輸出是f i l e d e s [ 0 ]的輸入。

  程式1- 1創建了一個從父進程到子進程的管道,並且父進程經由該管道向子進程傳送數據。

#include "my.h"

int main()
{
    int pfd[2],ret;
    ret = pipe(pfd);//創建管道
    if(ret<0)
    {   
        perror("pipe error!");
        exit(-1);
    }   
    pid_t pid = fork();
    if(pid<0)
    {   
        perror("fork error!");
        exit(-1);
    }   
    else if(pid>0)//父進程
    {   
        close(pfd[0]);
        int num;
        puts("please input your num:");
        scanf("%d",&num);
        write(pfd[1],&num,sizeof(num));
        //wait(NULL);
    }   
    else //子進程
    {   
        close(pfd[1]);
        int num;
        read(pfd[0],&num,sizeof(num));
        printf("num:%d\n",num);
    }
    return 0;
}

  註:頭文件my.h見這篇博客:http://www.cnblogs.com/liudw-0215/p/8946879.html 

  運行示例,如下圖:

  

  接下來介紹幾個跟管道有關的函數。

  2、dupd u p 2函數  

  下麵兩個函數都可用來複制一個現存的文件描述符:

  #include <unistd.h>

  int dup(intf i l e d es) ;
  int dup2(int f i l e d e s, int f i l e d e s 2) ;
  兩函數的返回:若成功為新的文件描述符,若出錯為- 1
  由d u p返回的新文件描述符一定是當前可用文件描述符中的最小數值。用 d u p 2則可以用f i l e d e s 2
  參數指定新描述符的數值。如果 f i l e d e s 2已經打開,則先將其關閉。如若f i l e d e s等於f i l e d e s 2,則
  d u p 2返回f i l e d e s 2
,而不關閉它。

  優化程式1-1,程式1-2如下:

#include "my.h"

int main()
{
    int pfd[2],ret;
    ret = pipe(pfd);
    if(ret<0)
    {   
        perror("pipe error!");
        exit(-1);
    }   
    pid_t pid = fork();
    if(pid<0)
    {   
        perror("fork error!");
        exit(-1);
    }   
    else if(pid>0)
    {   
        close(pfd[0]);
        int num;
        puts("please input your num:");
        scanf("%d",&num);
        write(pfd[1],&num,sizeof(num));
        wait(NULL);
    }   
    else
    {   
        close(pfd[1]);
        dup2(pfd[0],STDIN_FILENO);//pfd[0]複製到標準輸入
        int num;
        read(STDIN_FILENO,&num,sizeof(num));
        printf("num:%d\n",num);
    }
    return 0;
}

  

3、popenp c l o s e函數  

 因為常見的操作是創建一個連接到另一個進程的管道,然後讀其輸出或向其發送輸入,所

以標準I / O庫為實現這些操作提供了兩個函數 p o p e np c l o s e。這兩個函數實現的操作是:創建
一個管道, f o r k一個子進程,關閉管道的不使用端, e x e c一個s h e l l以執行命令,等待命令終止。
  #include <stdio.h>
  FILE *popen(const char * c m d s t r i n g, const char * t y p e) ;
  返回:若成功則為文件指針,若出錯則為 N U L L
  
  int pclose(FILE * f p) ;
  返回: c m d s t r i n g的終止狀態,若出錯則為 - 1
  函數popen 先執行f o r k,然後調用e x e c以執行c m d s t r i n g,並且返回一個標準 I / O文件指針。
  如果t y p e"r",則文件指針連接到c m d s t r i n g的標準輸出
  如果t y p e "w",則文件指針連接到c m d s t r i n g 的標準輸入

  程式1-3將用popen函數實現下圖功能:

  

  

#include "my.h"

int main()
{
    int c;
    while((c = getchar()) != EOF)
    {   
        if(isupper(c))  //是否有大寫
            c = tolower(c);  //轉為小寫
        if(putchar(c) == EOF)
            puts("put error!");
        if(c == '\n')
            fflush(stdout);  //刷新標準輸出
    }   
    exit(0);
}

---isupper.c---

  

#include "my.h"
#define MAXLINE 4096

int main()
{
    char line[MAXLINE];
    FILE *fpin;

    if((fpin = popen("./upper","r")) == NULL)
        perror("popen error!");

    for(;;){
        fputs("prompt > ",stdout);
        fflush(stdout);
        if(fgets(line,MAXLINE,fpin) == NULL)
            break;
        if(fputs(line,stdout) == EOF)
            perror("puts error!");    
    }   
    if(pclose(fpin) == -1) 
        perror("pclose error!");

    putchar('\n');
    return 0;

}

---popen.c---

  運行演示如下圖:

 二、有名管道(命名管道)

  1、簡介

  命名管道有時被稱為FIFO。管道只能由相關進程使用,它們共同的祖先進程創建了管道。
但是,通過F I F O,不相關的進程也能交換數據。
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char * p a t h n a m e, mode_tm o d e) ;
返回:若成功則為0,若出錯則為 - 1
m k f i f o函數中m o de參數的規格說明與o p e n函數中的m o d e相同
一旦已經用 m k f i f o創建了一個 F I F O,就可用 o p e n打開它。確實,一般的文件 I / O函數
c l o s er e a dw r i t eu n l i n k等)都可用於F I F O

  程式2-1演示有名管道通信,一個寫端、一個讀端:

#include "my.h"

typedef struct{
    char name[16];
    int age;
    double height;
}Person;

int main()
{
    mkfifo("pipe",0644);//創建管道 名字為pipe
    int fd = open("pipe",O_WRONLY);
    if(fd < 0)
    {   
        perror("open error!");
        exit(-1);    
    }   
    
    Person p;
    puts("please input your name,age,height:");
    scanf("%s%d%lf",p.name,&p.age,&p.height);
    write(fd,&p,sizeof(p));
    close(fd);

    return 0;
}
---fwrite.c---
#include "my.h"

typedef struct{
    char name[16];
    int age;
    double height;
}Person;

int main()
{
    int fd = open("pipe",O_RDONLY);
    if(fd < 0)
    {   
        perror("open error!");
        exit(-1);
    }   

    Person p;
    read(fd,&p,sizeof(p));
    printf("name:%-5sage:%-5dheight:%-5lf\n ",p.name,p.age,p.height);
    close(fd);
   unlink("pipe");//刪除管道文件
return 0; }
--- fread.c ---

  運行演示:先編譯fwrite.c生成w可執行用戶,./w執行,再編譯fread.c然後執行,寫端輸入數據,讀端輸出數據:

總結:主要介紹了進程間通信的管道,主要分為匿名管道和有名管道,還介紹了popen等函數

 

 





您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 在上一篇文章《路由其實也可以很簡單》,我們解決了路由問題,這篇文章,我們來研究剩下的另一個問題,為何我們的方法返回的是一個列表,輸出到客戶端的時候,變成json呢,大家應該還記得我們上一篇文章ProductsController的代碼: 在使用預設的約定的路由時,我們輸入地址:http://loca ...
  • 實驗所需資源: 1. tiny210(cortex a8) 2. QT 版本:5.6.2 3. PC 環境:UBUNTU 4. tslib:tslib 1.4 5. 交叉工具鏈:4.5.1 6. 開發板已裝載好 Linux 編譯 tslib 可能需要安裝的庫: ~~~~ sudo apt get i ...
  • Nginx編譯安裝Lua模塊 一、安裝Lua環境及相關庫 官網網址:https://github.com/openresty/lua nginx module 1. LuaJIT ` wget http://luajit.org/download/LuaJIT 2.0.2.tar.gz make i ...
  • 因業務需求,需要把lvs備機也使用上,故! 使用雙主,相互是主的同時也相互是備機。本人用nat測試發現RS無法實現負載均衡,故採用DR模式來實現非web端的負載均衡 lvs1: DIP 10.60.196.183 VIP 10.60.196.185 lvs2:DIP 10.60.196.184 VI ...
  • "Linux kernel的中斷子系統之(一):綜述" "Linux kernel的中斷子系統之(二):IRQ Domain介紹" "linux kernel的中斷子系統之(三):IRQ number和中斷描述符" "linux kernel的中斷子系統之(四):High level irq eve ...
  • TIP:Tab鍵可以自動補全命令 首先要瞭解Linux樹形結構 1、/- 根每一個文件和目錄從根目錄開始。只有root用戶具有該目錄下的寫許可權。請註意,/root是root用戶的主目錄,這與/.不一樣 2、/bin中 - 用戶二進位文件包含二進位可執行文件。在單用戶模式下,你需要使用的常見Linux ...
  • 這裡以redis-4.0.9為例 我自己為了好方便管理自己的軟體包,就在/usr/local/目錄下創建了一個software目錄 mkdir /usr/local/software cd /usr/local/software mkdir /usr/local/software cd /usr/l ...
  • 這是我在Linux系統下寫的第一篇博客,花了一周的時間從Windows系統轉到Linux並且可以完成日常操作,能在Linux系統下完成開發,運用各種開發工具,寫各種語言小程式和JavaEE。 經過這一周後,我的感覺就是,Linux太好玩了!!! 感受一下我的桌面: Linux和Windows最大的區 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...