一、popen
管道常見的操作是創建一個管道連接到另一個進程,然後讀其輸出或向其輸入端發送數據
標準I/O庫提供了函數popen, 該函數是:創建一個管道,調用fork產生一個子進程,關閉管道的不使用端,
執行一個shell以運行命令,然後等待命令終止。
#include <stdio.h>
FILE *popen(const char *command, const char *type);
返回:若成功則爲文件指針,若出錯則爲NULL
如果type爲r, 那麼調用進程讀進command的標準輸出
如果type爲w, 那麼調用進程寫到command的標準輸入
測試代碼:
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *fp = NULL;
char buff[1024] = {0};
char command[1024] = {0};
memset(command, 0x00, sizeof(command));
snprintf(command, sizeof(command), "%s", "ls");
fp = popen(command, "r");
memset(buff, 0x00, sizeof(buff));
while(fgets(buff, sizeof(buff), fp) != NULL)
{
printf("buff[%s]\n", buff);
memset(buff, 0x00, sizeof(buff));
}
fclose(fp);
return 0;
}
二、 pipe
int pipe(int fd[2]);
返回兩個文件描述符,fd[0]和fd[1], 前者打開來讀,後者打開來寫
成功返回0, 出錯返回-1
測試代碼:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main(void)
{
char writebuff[1024] = {0};
char readbuff[1024] = {0};
char readbuff2[1024] = {0};
int pipe_in[2], pipe_out[2];
pid_t pid;
printf("start test_pipe\n");
pipe(&pipe_in); // 創建父進程中用於讀取數據的管道
pipe(&pipe_out); // 創建父進程中用於寫入數據的管道
if ( (pid = fork()) == 0) { // 子進程
close(pipe_in[0]); // 關閉父進程的讀管道的子進程讀端
close(pipe_out[1]); // 關閉父進程的寫管道的子進程寫端
dup2(pipe_in[1], STDOUT_FILENO); // 複製父進程的讀管道到子進程的標準輸出
dup2(pipe_out[0], STDIN_FILENO); // 複製父進程的寫管道到子進程的標準輸入
close(pipe_in[1]); // 關閉已複製的讀管道
close(pipe_out[0]); // 關閉已複製的寫管道
// 從標準輸入讀取數據
read(STDIN_FILENO, readbuff2, sizeof(readbuff2));
// 使用exec執行命令
execl("/bin/sh", "sh", "-c", readbuff2, NULL);
} else { // 父進程
close(pipe_in[1]); // 關閉讀管道的寫端
close(pipe_out[0]); // 關閉寫管道的讀端
// 向pipe_out[1]中寫數據
snprintf(writebuff, sizeof(writebuff), "%s", "ls");
write(pipe_out[1],writebuff,strlen(writebuff));
// 這裏sleep 3秒,爲了是確認子進程先執行完成
sleep(3);
// 從pipe_in[0]中讀結果
read(pipe_in[0], readbuff, sizeof(readbuff));
printf("readbuff[%s]\n", readbuff);
close(pipe_out[1]); // 關閉寫管道
close(pipe_in[0]); // 關閉讀管道
// 使用wait系列函數等待子進程退出並取得退出代碼
waitpid(pid, NULL,0);
}
return 0;
}
三、socketpair
#include <sys/socket.h>
int socketpair(int family, int type, int protocol, int socketfd[2]);
返回0成功,返回-1出錯
family必須是AF_LOCAL或者AF_UNIX, type可以是SOCK_STREAM或者SOCK_DGRAM, protocol必須是0
創建的兩個套接字描述符sockefd[0]和sockefd[1]都是可讀寫
#include <stdio.h>
#include <string.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
int main(void)
{
char writebuff[1024] = {0};
char readbuff[1024] = {0};
int fd[2];
pid_t pid;
socketpair(AF_UNIX, SOCK_STREAM, 0, fd) ;// 創建管道
if ( (pid = fork()) == 0) { // 子進程
close(fd[0]); // 關閉管道的父進程端
dup2(fd[1], STDOUT_FILENO); // 複製管道的子進程端到標準輸出
dup2(fd[1], STDIN_FILENO); // 複製管道的子進程端到標準輸入
close(fd[1]); // 關閉已複製的讀管道
// 使用exec執行命令
execl("/bin/sh", "sh", "-c", "sort", NULL);
} else { // 父進程
close(fd[1]); // 關閉管道的子進程端
// 往fd[0]中寫數據
snprintf(writebuff, sizeof(writebuff), "%s", "j am king\n");
write(fd[0],writebuff,strlen(writebuff));
memset(writebuff, 0x00, sizeof(writebuff));
snprintf(writebuff, sizeof(writebuff), "%s", "i am queue\n ");
write(fd[0],writebuff,strlen(writebuff));
// 通知對端數據發送完畢
shutdown(fd[0], SHUT_WR);
// 從fd[0]中讀數據
read(fd[0], readbuff, sizeof(readbuff));
printf(" readbuff[%s]\n", readbuff);
/* 讀取剩餘數據 */
close(fd[0]); // 關閉管道
// 使用wait系列函數等待子進程退出並取得退出代碼
waitpid(pid, NULL,0);
}
}