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