管道由pipe函数创建,只能提供单向的数据传送
#include<unistd.h>
int
pipe(int fd[2])
此函数参数fd为两个文件描述符:fd[0],fd[1],一个用来读,一个用来写。
管道是由单个进程创建的,但是只在单个进程内使用的情况很少,一般是用来提供父子进程间的通信的。首先一个进程创建一个管道,然后派生出一个自身的拷贝;
接着,父进程关闭此管道的读出端,而子进程关闭管道的写入端。至此,父子进程之间就建立起了单一方向的数据流的通道。
代码说话
实现父进程通过管道向子进程传送字符串,再通过子进程输出到屏幕
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
int n,fd[2];
pid_t pid;
char line[1024];//缓冲区
if(pipe(fd)<0)//创建管道fd[0]读,fd[1]写
exit(0);
if((pid = fork())<0)//创建子进程
exit(0);
else if(pid > 0) {//fork函数对父进程和子进程都有返回值,子进程是0,父进程的返回值是子进程的ID(供内核识别)
close(fd[0]);//关闭管道读出端
write(fd[1],"I am from parent\n",19);
}
else{
close(fd[1]);
n = read(fd[0],line,1024);
write(STDOUT_FILENO,line,n);
}
exit(0);
}
/*实现数据双向传送。客户端从标准输入中读入一个目录的路劲名,并把它写入管道。
*服务器从管道读出路径名,并查看此目录是否存在。如果存在,则读此目录,并将目录下的文件写入另一个管道
*作为对客户端的回应。如果目录不存在,就写入一条错误信息。客户端随后从管道读出响应并把它写到标准输出
*/
#include <unistd.h>
#include <dirent.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define bufflen 1024
void err_sys(char *info)
{
fprintf(stderr, "%s:%s\n",info,strerror(errno));
exit(EXIT_FAILURE);
}
void server(int readfd,int writefd){
ssize_t n;
char buff[bufflen],*ptr;
struct dirent *dirp;//
DIR *dp;
if((n = read(readfd,buff,bufflen))==0)//因为opendir读目录要读字符串
exit(0);
buff[n] ='\0';//字符串的象征
ptr = buff + n;//ptr指向缓存中的第n个内存单元
if((dp = opendir(buff)) == NULL)//打开目录
snprintf(ptr,sizeof(buff)-n,"not find\n");
else{
while((dirp = readdir(dp))!=NULL){
if(strcmp(dirp->d_name,".")==0||strcmp(dirp->d_name,"..")==0)//'.'表示当前目录,'..'表示父目录
continue;
strcpy(ptr,dirp->d_name);//将目录名字复制到ptr指向的缓冲区内存单元中,会自动加'\0'
n = strlen(dirp->d_name);
ptr+=n;//移动指针
*ptr=' ';//置空把最后的'\0'去掉,不然后面读取目录的时候遇到'\0'就不会读取了,造成只能读一个目录后面读取不到
ptr++;//指向下一个单元
}
*ptr='\0';
}
n = strlen(buff);
if((write(writefd,buff,n))!=n)//一次性写到管道1中
exit(0);
closedir(dp);
}
/*
*从标准输入中读入路径名,经管道传送给server,再从另一个管道读出server返回的内容,并将其打印到标准输出
*/
void client(int readfd,int writefd)
{
char buff[bufflen];
int len;
size_t n;
fgets(buff,bufflen,stdin);//读一行,要留一个字符存放'\0'
len = strlen(buff);//不包括'\0'
if(buff[len-1] == '\n')
len--;
if((write(writefd,buff,len))!=len)//将buff中的内容写入writefd指向的文件中,pipe1[1]
exit(0);
while((n = read(readfd,buff,bufflen))>0)//从readfd(pipe2[0])指向的文件中读取bufferlen个字节内容读到buff中
if((write(STDOUT_FILENO,buff,n))!=n)//STDOUT_FILENO在<unistd.h>
exit(0);
printf("\n");
}
/*
程序创建两个双向管道。此后父进程调用client函数,子进程调用server()函数实现数据的双向传递。
子进程调用server向管道中写入数据然后调用exit函数终止退出,然后变成一个僵尸进程(子进程自己终止,父进程仍在运行,且不等待该子进程结束)。
在子进程终止时,内核给父进程发送一个SIGCHLD信号,但此时父进程并没有捕获这个信号,而此信号行为就是忽略。此后不久,父进程的client函数
从子进程传回信息后返回,紧接着就调用waitpid函数来取得已终止子进程的终止状态。要是父进程没有调用waitpid.而是直接终止,那么子进程将会
变成孤儿进程,它的父进程也变成了init进程。
*/
int main(int argc,char **argv)
{
int n,pipe1[2],pipe2[2];
pid_t childpid;
if(pipe(pipe1)<0) //创建管道
err_sys("pipe1");
if(pipe(pipe2)<0)
err_sys("pipe2");
if((childpid = fork())>0){ //创建子进程,
close(pipe1[0]);//关闭父进程管道1读
close(pipe2[1]);//关闭父进程管道2写
client(pipe2[0],pipe1[1]);
waitpid(childpid,NULL,0);//取得已终止子进程的终止状态
exit(0);
}
else{//子进程pid=0
close(pipe1[1]);
close(pipe2[0]);
server(pipe1[0],pipe2[1]);
exit(0);
}
}