IPC 無名管道

2021-09-26 09:14:56 字數 4115 閱讀 6718

以下參考:

1.1 特點

1)它是半雙工的(即資料只能在乙個方向上流動),具有固定的讀端和寫端

2) 它只能用於具有親緣關係的程序之間的通訊(也是父子程序或者兄弟程序之間)

3)它可以看成是一種特殊的檔案,對於它的讀寫也可以使用普通的read、write 等函式。但是它不是普通的檔案,並不屬於其他任何檔案系統,並且只存在於記憶體中

1.2 原型

1.2.1 pipe()

#include int pipe(int fd[2]);    // 返回值:若成功返回0,失敗返回-1
當乙個管道建立時,它會建立兩個檔案描述符:fd[0]為讀而開啟,fd[1]為寫而開啟。如下圖

要關閉管道只需將這兩個檔案描述符關閉即可

用於得到shell命令的執行結果

#include file * popen(const char *command , const char *type );

int pclose(file *stream);

command: 是乙個指向以 null 結束的 shell 命令字串的指標。這行命令將被傳到 bin/sh 並使用 -c 標誌,shell 將執行這個命令

mode: 只能是讀或者寫中的一種,得到的返回值(標準 i/o 流)也具有和 type 相應的唯讀或只寫型別。如果 type 是 「r」 則檔案指標連線到 command 的標準輸出;如果 type 是 「w」 則檔案指標連線到 command 的標準輸入。

#include #include int main ()

; fp = popen("ls -l", "r"); /* 執行ls -l命令, 把管道接到標準輸出上, 返回值是標準i/o流 */

fread(buff, 1, 127, fp); /* 通過fread讀取標準輸出流 */

printf("%s\r\n", buff);

pclose(fp);

return 0;

}

1.3 例子

單個程序中的管道幾乎沒有任何用處。所以,通常呼叫 pipe 的程序接著呼叫 fork,這樣就建立了父程序與子程序之間的 ipc 通道。如下圖所示:

以下參考:

2.1 功能

fork 這個英文單詞在英文裡是"分叉"意思, fork() 這個函式作用也很符合這個意思. 它的作用是複製當前程序(包括程序在記憶體裡的堆疊資料)為1個新的映象. 然後這個新的映象和舊的程序同時執行下去. 相當於本來1個程序, 遇到fork() 函式後就分叉成兩個程序同時執行了. 而且這兩個程序是互不影響

2.2 區分主程序和子程序

實際應用中, 單純讓程式分叉意義不大, 我們新增乙個子程式, 很可能是為了讓子程序單獨執行一段**. 實現與主程序不同的功能

實際上, fork() 有返回值, 而且在兩條程序中的返回值是不同的, 在主程序裡 fork()函式會返回子程序的pid, 而在子程序裡會返回0!

2.3 使用exit() 函式令子程序在if 判斷內結束

子程序和主程序在if判斷的範圍內執行了不同的**, if 執行完成後, 他們還是會各自執行後面的**。通常這不是我們期望的, 我們更多時會希望子程序執行一段特別的**後就讓他結束, 後面的**讓主程式執行就行了。

這個實現起來很簡單, 在子程式的if 條件內最後加上exit() 函式就ok了。

2.4 使用wait() 函式主程式等子程式執行完成(退出)後再執行

2.5 exec 函式組

#include int execl(const char *path, const char *arg, ...);  

int execlp(const char *file, const char *arg, ...);

int execle(const char *path, const char *arg, ..., char *const envp);

int execv(const char *path, char *const ar**);

int execvp(const char *file, char *const ar**);

int execve(const char *path, char *const ar**, char *const envp);

可以見到這6個函式名字不同, 而且他們用於接受的引數也不同. 實際上他們的功能都是差不多的, 因為要用於接受不同的引數所以要用不同的名字區分它們, 畢竟c語言沒有函式過載的功能嘛…

但是實際上它們的命名是有規律的:

exec[l or v][p][e]

exec函式裡的引數可以分成3個部分, 執行檔案部分, 命令引數部分, 環境變數部分.

例如我要執行1個命令 ls -l /home/gateman

執行檔案部分就是 「/usr/bin/ls」

命令參賽部分就是 「ls」,"-l","/home/gateman",null 見到是以ls開頭 每1個空格都必須分開成2個部分, 而且以null結尾的啊.

環境變數部分, 這是1個陣列,最後的元素必須是null 例如 char * env = ;

好了說下命名規則:

e後續, 引數必須帶環境變數部分, 環境變零部分引數會成為執行exec函式期間的環境變數, 比較少用

l 後續, 命令引數部分必須以"," 相隔, 最後1個命令引數必須是null

v 後續, 命令引數部分必須是1個以null結尾的字串指標陣列的頭部指標. 例如char * pstr就是1個字串的指標, char * pstr 就是陣列了, 分別指向各個字串.

p後續, 執行檔案部分可以不帶路徑, exec函式會在$path中找

注意, exec函式會取代執行它的程序, 也就是說,一旦exec函式執行成功, 它就不會返回了, 程序結束. 但是如果exec函式執行失敗, 它會返回失敗的資訊, 而且程序繼續執行後面的**!

通常exec會放在fork() 函式的子程序部分, 來替代子程序執行啦, 執行成功後子程式就會消失, 但是執行失敗的話, 必須用exit()函式來讓子程序退出!

#include #include void parent_execute()

}void child_execute_shell_script()

; char *execv_str1 = ;

// if (execv("/bin/echo", execv_str1) < 0)

if (execv("/bin/bash", execv_str) < 0)

}void child_execute()

exit(0);

}/* fd[0]: read, fd[1]: write */

void child_pipe_recv(int fd[2])

;

printf("[child_recv]start\r\n");

close(fd[1]); /* child recv only*/

read(fd[0], buff, 20);

printf("[child_recv]%s\r\n", buff);

printf("[child_recv]finish\r\n");

}void parent_pipe_send(int fd[2])

int main ()

;

printf("i am main, id is %d\r\n", getpid());

if (pipe(pipe_fd) < 0)

fpid = fork();

if (fpid < 0)

else if (fpid == 0)

else

printf("result is %d\r\n", count);

return 0;

}

linux管道(無名管道)

首先管道是程序之間的乙個單向資料流,它的資料流向由核心管理,只能從乙個程序流向另外乙個程序,乙個程序向管道寫入資料,另外乙個程序從這個管道讀取資料。在使用管道 無名管道 時,只能用在父子程序或者親屬程序之間,若要用在任意程序之間則需要使用fifo 有名管道 如圖程序ab通過管道進行資料交換。程序a通...

Linux管道(無名管道)

是一套免費使用和自由傳播的類unix作業系統,是乙個基於posix和unix的多使用者 多工 支援多執行緒和多cpu的作業系統。它能執行主要的unix工具軟體 應用程式和網路協議。它支援32位和64位硬體。linux繼承了unix以網路為核心的設計思想,是乙個效能穩定的多使用者網路作業系統。它主要用...

無名管道性質

pipe函式。pipe buf ubunt下為65536.寫性質。讀端關閉時,寫入資料會受到核心傳來的sigpipe訊號。讀端未關閉,當管道內已經填滿了pipe buf而未有讀出時,則會阻塞在write函式中,直到管道另一邊有讀出則繼續寫入管道直到寫完。讀性質。寫端關閉時,read函式返回0.寫端存...