读书笔记:第4章 管道和FIFO (1)

        《UNIX网络编程:卷2》P35-P37:图4-8、4-9、4-10 使用两个管道的客户-服务器程序

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/wait.h>
void client(int readfd, int writefd);
void server(int readfd, int writefd);
/* P35 mainpipe.c */
int main(int argc, char *argv[])
{
    int     pipe1[2], pipe2[2];
    pid_t   childpid;
    if (pipe(pipe1) < 0) {           // 创建管道1
        fprintf(stderr, "pipe error: %s\n", strerror(errno));
        exit(1);
    }   
    if (pipe(pipe2) < 0) {           // 创建管道2
        fprintf(stderr, "pipe error: %s\n", strerror(errno));
        exit(1);
    }   
    if ((childpid = fork()) < 0) {  // 创建新进程
        fprintf(stderr, "fork error: %s\n", strerror(errno));
        exit(1);
    } else if (childpid == 0) {     // 子进程
        close(pipe1[1]);            // 关闭管道1的写端
        close(pipe2[0]);            // 关闭管道2的读端
        server(pipe1[0], pipe2[1]);
        exit(0);
    }   
    // 父进程
    close(pipe1[0]);                // 关闭管道1的读端
    close(pipe2[1]);                // 关闭管道2的写端
    client(pipe2[0], pipe1[1]);
    waitpid(childpid, NULL, 0);     // 获取已终止子进程的终止状态
    exit(0);
}
/* P36 client.c */
#define MAXLINE 1024
void client(int readfd, int writefd)
{
    size_t      len;
    ssize_t     n;  
    char        buff[MAXLINE];
    fgets(buff, MAXLINE, stdin);    // 从标准输入读路径名字符串
    len = strlen(buff);
    if (buff[len-1] == '\n')        // 删除存入的换行符
        len--;
    // 将路径字符串写入管道
    if(write(writefd, buff, len) != len){
        fprintf(stderr, "write error: %s\n", strerror(errno));
        exit(1);
    }
    // 从管道读取由服务器写入的数据,并将其写到标准输出
    while ((n = read(readfd, buff, MAXLINE)) > 0)
        write(STDOUT_FILENO, buff, n);
}
/* P37 server.c */
void server(int readfd, int writefd)
{
    int         fd;
    ssize_t     n;
    char        buff[MAXLINE];
    // 从管道读出由客户端写入的路径名
    if ((n = read(readfd, buff, MAXLINE)) < 0) {
        fprintf(stderr, "read error: %s\n", strerror(errno));
        exit(1);
    } else if (n == 0) {
        fprintf(stderr, "end-of-file while reading pathname\n");
        exit(1);
    }
    buff[n] = '\0';     // 以空字符作为结尾 
    // 打开所请求的文件
    if ((fd = open(buff, O_RDONLY)) < 0) {
        // 打开文件出错
        snprintf(buff + n, sizeof(buff) - n, ": can't open, %s\n", strerror(errno));
        n = strlen(buff);
        write(writefd, buff, n);        // 将出错信息写入管道
    } else {
        // 打开文件成功,将文件内容复制到管道中
        while((n = read(fd, buff, MAXLINE)) > 0)
            write(writefd, buff, n);
        close(fd);
    }
}

        main函数创建两个管道并用fork生成一个子进程。客户然后作为父进程运行,服务器则作为子进程运行。第一个管道用于从客户向服务器发送路径名,第二个管道用于从服务器向客户发送该文件的内容(或者一个出错消息)。

        运行程序:

$ ./mainpipe 
Makefile            一个由四行文件构成的文件
mainpipe:
gcc mainpipe.c -o mainpipe -Wall
clean:
rm mainpipe
$ ./mainpipe 
/etc/shadow        一个我们不能读的文件
/etc/shadow: can't open, Permission denied
$ ./mainpipe 
/no/such/file        一个不存在的文件
/no/such/file: can't open, No such file or directory

你可能感兴趣的:(读书笔记,《UNIX网络编程》)