加入星計劃,您可以享受以下權(quán)益:

  • 創(chuàng)作內(nèi)容快速變現(xiàn)
  • 行業(yè)影響力擴散
  • 作品版權(quán)保護
  • 300W+ 專業(yè)用戶
  • 1.5W+ 優(yōu)質(zhì)創(chuàng)作者
  • 5000+ 長期合作伙伴
立即加入
  • 正文
    • 相關(guān)要點
    • 優(yōu)缺點
    • 內(nèi)部實現(xiàn)
    • 應用案例
    • 相關(guān)參考
    • 思考技術(shù),也思考人生
  • 推薦器件
  • 相關(guān)推薦
  • 電子產(chǎn)業(yè)圖譜
申請入駐 產(chǎn)業(yè)圖譜

Linux-C編程 進程通信 以文件讀寫的方式和進程通訊

2020/12/15
252
閱讀需 12 分鐘
加入交流群
掃碼加入
獲取工程師必備禮包
參與熱點資訊討論

快速上手popen()

?

該函數(shù)用于運行指定命令,并且讓剛啟動的程序看起來像文件一樣可以被讀寫。

2 個 demo

1) 從外部程序中讀數(shù)據(jù):

int?main(int?argc,?char?**argv)
{
????FILE?*fp;
????char?buf[100];
????int?i?=?0;

????fp?=?popen("ls?-1X",?"r");

????if?(fp?!=?NULL)?{
????????while(fgets(buf,?100,?fp)?!=?NULL)?{
????????????printf("%d:?%s",?i++,?buf);
????????}
????????pclose(fp);
????????return?0;
????}
????return?1;
}

運行效果:

$?./001_popen_r?
0:?001_popen_r
1:?002_popen_w
2:?001_popen_r.c
3:?002_popen_w.c
4:?004_popen_intern.c

2) 寫數(shù)據(jù)到外部程序:

int?main(int?argc,?char?*argv)
{
????FILE?*fp?=?NULL;
????char?buffer[BUFSIZE];

????sprintf(buffer,?"hello?worldn");

????fp?=?popen("od?-tcx1",?"w");
????if?(fp?!=?NULL)?{
????????fwrite(buffer,?sizeof(char),?strlen(buffer),?fp);
????????pclose(fp);
????????return?0;
????}
????return?1;
}

運行效果:

0000000???h???e???l???l???o???????w???o???r???l???d??n
?????????68??65??6c??6c??6f??20??77??6f??72??6c??64??0a
0000014

相關(guān)要點

函數(shù)原型

FILE?*popen(const?char?*command,?const?char?*type);

popen() 會先執(zhí)行 fork,然后調(diào)用 exec 執(zhí)行 command,并且返回一個標準 I/O 文件指針。

type = "r":

  • 文件指針連接到 command 的標準輸出。

type = "w":

  • 文件指針連接到 command 的標準輸入。

點擊查看大圖

優(yōu)缺點

優(yōu)點:

  • 由于調(diào)用了 shell,所以可以支持通配符 (例如*.c) 等各種 shell 擴展特性;減少了代碼量;

缺點:

  • 要啟動 2 個程序:shell 和 目標程序,調(diào)用成本略高,比起直接 exec 某個程序來說要慢一些;

內(nèi)部實現(xiàn)

popen() 的內(nèi)部實現(xiàn)思路如下:

FILE?*_popen(const?char?*command,?const?char?*type)
{
????pipe()
????fork();
????if?(pid?>?0)
????????close()?child's?fd
????????return?fdopen()?parent's?fd
????else
????????close(parent's?fd)
????????dup2()?child's?data?fd?to?stdin?or?stdout
????????close()?child's?fd
????????exec("/bin/sh?-c")?command
}
  1. 創(chuàng)建一個管道,用于父子進程間的通訊;父進程:
    • 關(guān)閉未使用的管道端;返回父進程數(shù)據(jù)管道端的 FILE *, 它可能連接父進程的 stdin / stdout;

子進程:

  • 關(guān)閉未使用的管道端;重定位子進程的數(shù)據(jù)管道端到 stdin / stdout;執(zhí)行目標命令;

初步的代碼實現(xiàn):

FILE?*_popen(const?char?*command,?const?char?*type)
{
????int?pfp[2];
????int?parent_end,?child_end;
????int?pid;

????if?(*type?==?'r')?{
????????parent_end?=?READ;
????????child_end?=?WRITE;
????}?else?if?(*type?==?'w')?{
????????parent_end?=?WRITE;
????????child_end?=?READ;
????}?else?{
????????return?NULL;
????}

????pipe(pfp);
????pid?=?fork();
????if?(pid?>?0?)?{
????????close(pfp[child_end]);
????????return?fdopen(pfp[parent_end],?type);
????}?else?{
????????close(pfp[parent_end]);
????????dup2(pfp[child_end],?child_end);
????????close(pfp[child_end]);
????????execl("/bin/sh",?"sh",?"-c",?command,?NULL);
????????exit(0);
????}
????return?NULL;
}

這里的實現(xiàn)有一些不足的地方,例如:

為了便于閱讀,省略了錯誤檢查;

沒有保存子進程的 pid,后續(xù)無法使用 wait() 進行收尸;

一個進程可能調(diào)用 popen() 多次,需要用數(shù)組 / 鏈表來存儲所有子進程的 pid;

更完善的實現(xiàn)可以參考:

https://android.googlesource.com/platform/bionic/+/3884bfe9661955543ce203c60f9225bbdf33f6bb/libc/unistd/popen.c

應用案例

開源軟件 MJPG-steamer 為例。

MJPG-streamer 是什么?

簡單地說,就是一個開源的流媒體服務器

https://github.com/jacksonliam/mjpg-streamer

通過 mjpg-streamer,你可以通過 PC 瀏覽器訪問到板子上的攝像頭圖像。

MJPG-streamer 就是通過 popen() 來支持 CGI 功能的:

CGI 是早期出現(xiàn)的一種簡單、流行的服務端應用程序執(zhí)行接口,http server 通過運行 CGI 程序來完成更復雜的處理工作,在 MJPG-streamer . 里的相關(guān)代碼如下:

plugins/output_http/httpd.c

void?execute_cgi(int?id,?int?fd,?char?*parameter,?char?*query_string)
{
????//?prepare

????//?執(zhí)行瀏覽器指定的?CGI?程序
????f?=?popen(buffer,?"r");

????//?獲得?CGI?程序的輸出
????while((i?=?fread(buffer,?1,?sizeof(buffer),?f))?>?0)?{
????????if?(write(fd,?buffer,?i)?<?0)?{
????????????fclose(f);
????????????free(buffer);
????????????close(lfd);
????????????return;
????????}
????}

}

這里只是簡單地了解一下 MJPG-Streamer,有興趣的小伙伴們自行閱讀更多的代碼吧。

相關(guān)參考

Unix-Linux 編程實踐教程 / 11.4 popen: 讓進程看似文件

Linux 程序設計(第 4 版) / 13.3 將輸出送往 popen

Unix 環(huán)境高級編程第 3 版 / 15.3 函數(shù) popen 和 pclose

HTTP 權(quán)威指南

思考技術(shù),也思考人生

要學習技術(shù),更要學習如何生活。

你和我各有一個蘋果,如果我們交換蘋果的話,我們還是只有一個蘋果。但當你和我各有一個想法,我們交換想法的話,我們就都有兩個想法了。

嵌入式系統(tǒng) (Linux、RTOS、OpenWrt、Android) 和 開源軟件 感興趣,關(guān)注公眾號:嵌入式 Hacker。

覺得文章對你有價值,還請多多 轉(zhuǎn)發(fā)。

推薦器件

更多器件
器件型號 數(shù)量 器件廠商 器件描述 數(shù)據(jù)手冊 ECAD模型 風險等級 參考價格 更多信息
10M08SCE144C8G 1 Intel Corporation Field Programmable Gate Array, 8000-Cell, CMOS, PQFP144, 22 X 22 MM, 0.50 MM PITCH, ROHS COMPLIANT, PLASTIC, EQFP-144

ECAD模型

下載ECAD模型
$17.46 查看
M1A3P1000-PQG208I 1 Microchip Technology Inc Field Programmable Gate Array, 24576 CLBs, 1000000 Gates, 350MHz, CMOS, PQFP208
$393.19 查看
XC7A200T-3FFG1156E 1 AMD Xilinx Field Programmable Gate Array, 16825 CLBs, 1412MHz, 215360-Cell, CMOS, PBGA1156, FBGA-1156
$527.73 查看

相關(guān)推薦

電子產(chǎn)業(yè)圖譜