Unix网络编程-进程间通信---4、最初的Unix IPC -- 管道

1、客户端服务器需求
Unix网络编程-进程间通信---4、最初的Unix IPC -- 管道


2、int pipe(int fd[2])//返回两个文件描述符,fd[0]读,fd[1]写;

宏S_ISFIFO用来确定一个文件描述符或者文件是管道还是FIFO;

3、半双工通信管道的使用:

一对父子进程,由父进程创建一个管道,子进程复制副本;父进程关闭读fd[0],子进程关闭写fd[1];实现了单向父 ----> 子的通信
因为父进程创建的管道资源是属于父子进程公共分享的空间,这个资源只在父进程创建了一份;


4、如何理解who | sort | lp   ----->

实际上是终端bbsh创建了先创建了2个父进程管道空间和三个进程:

(1)piie()--->exec()

Unix网络编程-进程间通信---4、最初的Unix IPC -- 管道

4、如何实现全双工通信

(1)父进程创建两个管道,一个管道用于读,一个用于写
子进程捏住读和写句柄;
父进程也同时捏住读和写;
对于用户态来说,只需要往自己拿着的句柄当作普通文件是使用即可;
比如说父进程客户端-》先发送文件路径过去,write(fd1, pathname, n); 然后等着读文件的内容:read(fd2, buff, n);
同理子进程作为服务器:先接收文件路径:read(fd1, buff_pathname, n); 然后打开这个文件,再把内容发送给客户端write(fd2. buffcontex, n);
 

int main()
{
int pipe1[2],pipe2[2];;

pipe(pipe1);
pipe(pipe2);
childpid = fork();
if(child == 0) // 子进程--->服务器
{
    close(pipe1[1]);//关1写---》pipe1[0]用于读
    close(pipe2[0]);//关2读---》pipe2[1]用于写

    server(pipe1[0], pipe2[1]);  
    exit(0);
}
//父进程---》客户端
close(pipe1[0]);
close(pipe2[1]);
client(pipe1[1], pipe2[0]);

//pid_t waitpid(pid_t pid, int *status, int options);
waitpid(childpid, NULL, 0);//
exit(0);
}
//子进程调用exit的时候,将变成僵尸进程,内核会给父进程发送SIGCHILD信号,父进程默认是忽略的,但是此处使用了waitpid取得终止子进程的终止状态;
//如果没有waitpid的话,一旦父进程终止后,这个子进程将变成孤儿进程(托孤给init进程管理),内核将为此向init进程发送另外一个SIGCHLD信号
 

 

void client(int readfd, int writefd) //客户端从标准输入获取文件路径, 发送到服务器,然后接收文件内容
{
    fgets(buff, MAXLINE, stdin);//fgets会把\n字符也算进去,这样len就等于实际字节数+1(\n)了;
    len = strlen(buff);

    if(buff[len-1] == '\n')//这个是成立的
        len=len-1;
    write(writefd, buff, len);

    while( (n = read(readfd, buff, len))  > 0)//给完路径就等着接收数据了
    {
        printf("%s\n", buff);
   }
}

 

void server(int readfd, int writefd)//服务器先接收客户端发来的文件路径,然后打开文件,把文件内容发送给客户端
{

    n = read(readfd, buff, MAXLINE);
    buff[n] = '\0';//注意不是buff[n-1]

    fd = open(buff, O_RDONLY);
    if(fd < 0)//打开出错了,告诉客户端发过来的路径有问题
    {
        snprintf(buff + n, sizeof(buff) - n; ":can't open %s\n", strerror(errno));
        write(writefd, buff, n);
    }
    else
    {
        while((n = read(fd, buff, MAXLINE)) > 0)
        {
            write(writefd, buff, n);
       }
        close(fd);
    }

}

 

5、Unix网络编程---进程间通信书中提到某些系统通过单管道实现全双工通信,实际上再很多系统上是不支持的

#include<unistd.h>
#include<stdio.h>
int main(void)
{
        int fd[2], n;
        char c;
        pid_t childpid;

        pipe(fd);
        childpid = fork();
        if(childpid == 0)
        {
                sleep(3);
                n = read(fd[0], &c, 1);
                printf("child read %c\n", c);
                write(fd[0], "c", 1);
                exit(0);
        }
        waitpid(childpid, NULL, 0);

        write(fd[1], "p", 1);
        n = read(fd[1], &c, 1);
        printf("parents read %c\n", c);

        return 0;
}

 

6、标准IO也提供了操作管道的接口(这一块用到的是再学吧,跟用户输入有关)

#include<stdio.h>
FILE * popen (const char* command, const char *type);//其中command是一个
int pclose(FILE* stream);
 

 

 

 

上一篇:DPCM 压缩系统的实现和分析


下一篇:31.Linux-分析并制作环形缓冲区