Linux进程通信:管道

使用管道进行进程间通信

#include<stdio.h>
#include<unistd.h>

#define MSGSIZE 16

char *msg1="hello,world!#1";
char *msg2="hello,world!#2";
char *msg3="hello,world!#3";

int main(void)
{
    char inbuf[MSGSIZE];
    int p[2],j;

    /*open pipe */
    if(pipe(p)==-1)
    {
        perror("pipe call");
    }

    /*write down pipe*/
    write(p[1],msg1,MSGSIZE);
    write(p[1],msg2,MSGSIZE);
    write(p[1],msg3,MSGSIZE);

    /*read from pipe*/

    for(j=0;j<3;j++)
    {
        read(p[0],inbuf,MSGSIZE);
        printf("%s/n",inbuf);
    }

    return 0;
}

jiang@jiang-linux:~/unixprog/2011-3-20$ ./pipe.o 
hello,world!#1
hello,world!#2
hello,world!#3

父子进程

子进程写,父进程读:

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define MSGSIZE 16

char *msg1="hello,world!#1";
char *msg2="hello,world!#2";
char *msg3="hello,world!#3";

int main(void)
{
  char inbuf[MSGSIZE];
    int p[2],j;
    pid_t pid;

    /*open file*/
    if(pipe(p)==-1)
    {
        perror("pipe call");
        exit (1);
    }

    switch(pid=fork())
    {
        case -1:
            perror("fork call");
            exit (1);
        case 0:
            /*if child then close read file descript and writes down the pipe*/
            close(p[0]);
            write(p[1],msg1,MSGSIZE);
            write(p[1],msg2,MSGSIZE);
            write(p[1],msg3,MSGSIZE);
            break;
    default:
            /*if parent then closes write file descriptot and reads from the pipe*/

            close(p[1]);
            for(j=0;j<3;j++)
            {
                read(p[0],inbuf,MSGSIZE);
                printf("%s/n",inbuf);
            }
            wait(NULL);//??
    }
    exit(0);
}

jiang@jiang-linux:~/unixprog/2011-3-20$ gcc fork_pipe.c -o fork_pipe.o;./fork_pipe.o 
hello,world!#1
hello,world!#2
hello,world!#3


创建三个进程,2个写,1个读。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>


int main(void)
{
    char s[100];
    char wribuf1[10]="123456789";
    char wribuf2[10]="987654321";
    pid_t pid1,pid2,pid3;
    int p[2],j;
    if(pipe(p)==-1)
    {
        perror("pipe call");
    }
   switch(pid1=fork()) //write pipe 
     {
         case -1:
             perror("fork call");
             exit (1);
         case 0:  //child1 write pipe
             for(j=0;j<10;j++)
             {
                 
                 write(p[1],wribuf1,10);
             }
             exit(1);
         default:
             break;
             
     }

   switch(pid3=fork())  //child3 write pipe
     {
         case -1:
             perror("fork call");
             exit (1);
         case 0:  //child write pipe
             for(j=0;j<10;j++)
             {
                 
                 write(p[1],wribuf2,10);
             }
             exit(1);
         default:
             break;
     }
             
   switch(pid2=fork())  //read pipe
     {
         case -1:
             perror("fork call");
             exit (1);
         case 0:  //child write pipe
             for(j=0;j<100;j++)
             {
                 read(p[0],s,10);
                 printf("%s/n",s);
             }
             exit(1);
         default:
             break;
             
     }
  
     exit(0);
    
}

jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe3.c -o pipe3.o;./pipe3.o
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
123456789
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321
987654321


管道的容量:

#include<stdlib.h>
#include<signal.h>
#include<unistd.h>
#include<stdio.h>

long count;
void alrm_action(int signo);

int main(void)
{
    int p[2];

    long pipe_size;
    char c='x';
    static struct sigaction act;

    /* set up the signal handler*/
    act.sa_handler=alrm_action;
    sigfillset(&(act.sa_mask));

    /*create the pipe */
    if(pipe(p)==-1)
    {
        perror("pipe call");
        exit (1);
    }

    /* determine the size of pipe
      long fpathconf(int fd, int name);
         _PC_PIPE_BUF
     returns  the  size  of the pipe buffer, where fd must refer to a
 pipe or FIFO and path must refer to a FIFO.   The  corresponding
 macro is _POSIX_PIPE_BUF.
*/

    pipe_size=fpathconf(p[0],_PC_PIPE_BUF);
    printf("Maximum size of write to pipe:%ld bytes/n",pipe_size);

    /*set the signal handler*/
    sigaction(SIGALRM,&act,NULL);

    while(1)
    {
        /*set alarm*/
        alarm(20);

        /*write down pipe */
    write(p[1],&c,1);

        /*reset alarm--if no block没有阻塞的话就取消超时*/
        alarm(0);

        if((++count%10240)==0)//if is the multiple of 10240,print information
        {
            printf("%ld character in pipe/n",count);
        }


    }
}

void alrm_action(int signo)
{
    printf("write bolcked after %ld characters/n",count);
    exit(0);
}

结果不对,不知道为啥,最大的显示是4096,但又写了61440进去。。
jiang@jiang-linux:~/unixprog/2011-3-20$ gcc pipe_size.c -o pipe_size.o;./pipe_size.o
Maximum size of write to pipe:4096 bytes
10240 character in pipe
20480 character in pipe
30720 character in pipe
40960 character in pipe
51200 character in pipe
61440 character in pipe
write bolcked after 65536 characters


非阻塞读与写

/* nonblock pipe */
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<fcntl.h>
#include<errno.h>

#define MSGSIZE 6

int parent(int *);
int child(int *);

char *msg1="hello";
char *msg2="bye!!";

int main(void)
{
    int pfd[2];

    /*open pipe*/
    if(pipe(pfd)==-1)
    {
        fatal("pipe call");
    }

    /*set O_NONBLOCK flag for p[0]*/
    if(fcntl(pfd[0],F_SETFL,O_NONBLOCK)==-1)
    {
        fatal("fcntl call");
    }

    switch(fork())
    {
        case -1:
            fatal("fork call");
        case 0:
            /*child*/
            child(pfd);
        default:  /*parent*/
            parent(pfd);
    }


}

int parent(int *p)
{
    ssize_t nread;
    char buf[MSGSIZE];

    close(p[1]);//close pipe write

    for(;;)
    {//总结:read在读取管道时的返回值似乎跟读文件不太一样
        switch(nread=read(p[0],buf,6))//read返回-1表示发生错误,在读管道时表示空
        {
            case -1:
                /*check to see if nothing is in the pipe */
                if(errno==EAGAIN)
                {
             printf("pipe empty/n");
                         sleep(1);
                         break;
                }
            case 0://read返回0表示读到文件结构符,在读管道时表示管道关闭。子进程终止后管道的写就关闭了,
                        //父进程的写已经关闭了,所以认为管道关闭了。
                /*pipe has been closed */
                printf("End of conversation/n");
                exit(0);
            default://read pipe success
                printf("MSG=%s/n",buf);

        }
    }
}

int child(int *p)
{
    int count;
    
    close(p[0]);

    for(count=0;count<3;count++)
    {
        write(p[1],msg1,MSGSIZE);
        sleep(3);
    }

    /*send final message*/
    write(p[1],msg2,MSGSIZE);
    exit (0);

}

int fatal(char *s)
{
    perror("s");
    exit (1);
}

jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
End of conversation


如果在父进程中把 close(p[1]);//close pipe write注释掉,表示不要关闭写管道。结果父进程会无阻等待下去:

jiang@jiang-linux:~/unixprog/2011-3-20$ gcc nonblock_pipe.c -o nonblock_pipe.o;./nonblock_pipe.o
pipe empty
MSG=hello
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=hello
pipe empty
pipe empty
pipe empty
MSG=bye!!
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
pipe empty
^C


使用select处理多路管道

程序说明:父进程基于管道与三个子进程联系,除此之外,父进程还监听着标准输入。
/*server----creates three children and then services them */

#include<stdio.h>
#include<sys/time.h>
#include<sys/wait.h>
#include<stdlib.h>
#include<unistd.h>

#define    MSGSIZE 6
char *msg1="hello";
char *msg2="bye!!";

void parent(int p[][2]);
void child(int p[][2],int i);

int main(void)
{
    int pip[3][2];
    int i;

    /*create three communication pipes,and spawn three children */
  for(i=0;i<3;i++)
    {
        if(pipe(pip[i])==-1)
        {
            fatal("pipe call");
        }

        switch(fork())
        {
            case -1:     //error
                fatal("fork call");
            case 0:        //child
                child(pip,i);
        }

        
    }
    parent(pip);

        exit(0);

}

/*parent sits listening on all three pipes*/
void parent(int p[3][2])        //code for parent
{
    char buf[MSGSIZE],ch;
    fd_set set,master;
    int i;

    /*close all unwanted write file descriptors*/
/*    for(i=0;i<3;i++)
    {
        close(*(p+i)+1);
    }
*/
   close(p[0][1]);
   close(p[1][1]);
   close(p[2][1]);


    /*set the bit masks for the select system call*/
    FD_ZERO(&master);//initialize the mask pointed to by master*/
    FD_SET(0,&master);//set 0:listening stdin
    for(i=0;i<3;i++)
    {
        FD_SET(p[i][0],&master);//listening pipe read
    }

    /*select is called with no timeout,
     * it will block until an event occurs:all child exit
     * set=master means restore the state
     */
  while(set=master,select(p[2][0]+1,&set,NULL,NULL,NULL)>0)//select的第一个参数不知道什么意思
    {
        
        /*we mustn't forget information on standard input,
         * i.e. fd=0
         */
               if(FD_ISSET(0,&set))//listening stdin
                {
               printf("From statdard input:/n");
               read(0,&ch,1);
               printf("%c/n",ch);
                }

        for(i=0;i<3;i++)
        {
            if(FD_SET(p[i][0],&set))
            {
                if(read(p[i][0],buf,MSGSIZE)>0)
                {
                    printf("Message from child %d/n",i);
                    printf("MSG=%s/n",buf);
                }
            }
        }
   
        /*the server will return to the main program if all
         * the children have died
         */
        if(waitpid(-1,NULL,WNOHANG)==-1)
        {
            return;
        }

    }
    
}

void child(int p[][2],int i)
{
    int count;

    close(p[i][0]);//close read pipe

    for(count=0;count<2;count++)//each child write 2 msg 
    {
        write(p[i][1],msg1,MSGSIZE);
        /*pause for a random amount of time*/
        sleep(getpid()%4);
    }

    /*set final message*/
    write(p[i][1],msg2,MSGSIZE);
    exit(0);
}

int fatal(char *s)
{
    perror(s);
    exit(1);
}

结果:
jiang@jiang-linux:~/unixprog/2011321$ gcc select_pipe.c -o select_pipe.o;./select_pipe.o
Message from child 0
MSG=hello
Message from child 1
MSG=hello
Message from child 2
MSG=hello
Message from child 0
MSG=hello
a
Message from child 1
MSG=hello
Message from child 2
MSG=hello
From statdard input:
a
Message from child 0
MSG=bye!!
Message from child 1
MSG=bye!!
Message from child 2
MSG=bye!!
From statdard input://不知道为什么最后会输出这一句,似乎set没有重置


管道的例子

展示了管道和exec系统调用的使用,模拟了shell中的管道。难点是理解如何将ls的标准输出连接
到管道的写入端,将grep的标准输入连接到管道的输出端。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

/*join---join two commands by pipe*/
int join(char *com1[],char *com2[])
{
    int p[2],status;

    /*create child to run commands*/
    switch(fork())
    {
        case -1:
            fatal("1st fork call in join");
        case 0:
            break;//child
    default://parent
            wait(&status);
            return (status);//父进程等待子进程执行完毕后返回状态
    }

    /*remainder of rountine executed by child*/

    /*make pipe*/
    if((pipe(p))==-1)
        {
            fatal("pipe call in join");
        }

    /*create another process*/
    switch(fork())//孙进程将标准输出连接到管道的写入端
    {
        case -1:
            /*error*/
            fatal("2nd fork call in fork");
    case 0:
            /*the writing process*/
            dup2(p[1],1);  //make std.output go to pipe*/
            close(p[0]);/*save file descriptors??*/
            close(p[1]);

            execvp(com1[0],com1);//执行程序,将标准输出连接到管道的写入端
            /*if execvp returns,error has occured*/
            fatal("1st execvp call in join");
        default:
            /*the reading process*/
            dup2(p[0],0);//make std.input come from pipe子进程将标准输入连接到管道的写出端

            close(p[0]);
            close(p[1]);
            execvp(com2[0],com2);
            fatal("2nd execvp call in join");
    }
}



int main(void)
{
    char *one[4]={"ls","-1","/usr/lib",NULL};
    char *two[3]={"grep","^d",NULL};
    int ret;

    ret=join(one,two);
    printf("join returned %d/n",ret);
    exit(0);

}
int fatal(char *s)
{
    perror(s);
    exit(1);
}

jiang@jiang-linux:~/unixprog/2011321$ gcc join.c -o join.o;./join.o
dbus-1.0
default.sfx
desktopcouch
directfb-1.2-0
dkms
dpkg
dri
join returned 0


命名管道

FIFO编程:
一个程序用来向命名管道发送信息,一个接收信息。

sendmessage.c

#include<fcntl.h>
#include<stdio.h>
#include<errno.h>
#include<unistd.h>
#include<stdlib.h>
#include<string.h>

#define MSGSIZE  63

char *fifo="fifo";

int main(int argc,char **argv)
{
    int fd,j,nwrite;
    char msgbuf[MSGSIZE];

    if(argc<2)
    {
        fprintf(stderr,"Usage:sendmessage msg.../n");
        exit(1);
    }

    /*open fifo with O_NONBLOCK set */
    if((fd=open(fifo,O_WRONLY|O_NONBLOCK))<0)//非阻塞式打开
    {
        fatal("fifo open failed");
    }

    /*send message*/
    for(j=1;j<argc;j++)
    {
        if(strlen(argv[j])>MSGSIZE)
            {
                fprintf(stderr,"message too long %s/n",argv[j]);
                continue;
                }
        strcpy(msgbuf,argv[j]);

        if((nwrite=write(fd,msgbuf,MSGSIZE+1))==-1)
        {
            fatal("message write failed");
        }
    }

    exit(0);
}


int fatal(char *s)
{
    perror(s);
    exit(1);
}

recemessage.c
/*recemessage---receive message via fifo*/

#include<fcntl.h>
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<errno.h>

#define MSGSIZE  63
char *fifo="fifo";

int main(int argc,char **argv)
{
    int fd;
    char msgbuf[MSGSIZE+1];

    /*create fifo,if it doedn't already exist*/
    if(mkfifo(fifo,0666)==-1)
    {
        if(errno!=EEXIST)
        {
            fatal("receiver:mkfifo");
        }
    }

    /*open fifo for reading and writing*/
    if((fd=open(fifo,O_RDWR))<0)
    {
        fatal("fifo open failed");
    }

    /*receive message*/
    for(;;)
    {
        if(read(fd,msgbuf,MSGSIZE+1)<0)
        {
            fatal("message read failed");
        }
        /*
         * printf out message;in read life
         * something more interesting would 
         * be done
         */
        printf("message received:%s/n",msgbuf);
    }
    exit(0);
}

int fatal(char *s)
{
    perror(s);
    exit (1);
}

运行结果:
jiang@jiang-linux:~/unixprog/2011321$ ./recemessage.o &
[1] 2222
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello''world'
message received:helloworld
jiang@jiang-linux:~/unixprog/2011321$ ./sendmessage.o 'hello' 'world'
message received:hello
message received:world

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值