【Linux】管道的通信總結

一、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);
	}
}


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