《UNIX网络编程:卷2》P52-P55:图4-25、4-27、4-28、4-29、4-30
-----------------------------------------------------------------
图4-25 我们的mymesg结构及相关定义
mesg.h文件如下:
/* P52 mesg.h */ #ifndef MESG_H__ #define MESG_H__ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <sys/wait.h> #include <limits.h> #define MAXMESGDATA (PIPE_BUF - 2 * sizeof(long)) #define MESGHDRSIZE (sizeof(struct mymesg) - MAXMESGDATA) struct mymesg { long mesg_len; // 消息长度 long mesg_type; // 消息类型 char mesg_data[MAXMESGDATA]; }; void client(int readfd, int writefd); void server(int readfd, int writefd); ssize_t mesg_send(int fd, struct mymesg *mptr); ssize_t mesg_recv(int fd, struct mymesg *mptr); #endif
-----------------------------------------------------------------
pipemesg.c文件如下:
#include "mesg.h" /* 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); } /* 图4-27 mesg_send函数 */ /*P53 mesg_send.c */ ssize_t mesg_send(int fd, struct mymesg *mptr) { // 写入消息 return(write(fd, mptr, MESGHDRSIZE + mptr->mesg_len)); } /* 图4-28 mesg_recv函数 */ /* P53 mesg_recv.c */ ssize_t mesg_recv(int fd, struct mymesg *mptr) { size_t len; ssize_t n; // 读取消息头部,获取消息长度信息 if ((n = read(fd, mptr, MESGHDRSIZE)) < 0) { fprintf(stderr, "read error: %s\n", strerror(errno)); exit(1); } else if (n == 0) { return(0); } else if (n != MESGHDRSIZE) { fprintf(stderr, "message header: expected %d, got %d\n", (int)MESGHDRSIZE, (int)n); exit(1); } if ((len = mptr->mesg_len) > 0) { // 读出真正的消息 if ((n = read(fd, mptr->mesg_data, len)) < 0){ fprintf(stderr, "read error: %s\n", strerror(errno)); } else if (n != len){ fprintf(stderr, "message data: expected %d, got %d\n", (int)len, (int)n); exit(0); } } return (len); } /* 图4-29 我们的使用消息的client函数*/ /* P54 client.c */ void client(int readfd, int writefd) { size_t len; ssize_t n; struct mymesg mesg; // 从标准输入读路径名 fgets(mesg.mesg_data, MAXMESGDATA, stdin); len = strlen(mesg.mesg_data); if (mesg.mesg_data[len-1] == '\n') len--; // 删除换行符 mesg.mesg_len = len; // 消息长度 mesg.mesg_type = 1; // 消息类型 // 将消息发送给服务器 if (mesg_send(writefd, &mesg) < 0) { fprintf(stderr, "mesg_send error: %s\n", strerror(errno)); exit(1); } // 通过循环,读出服务器发送回的所有内容 while ((n = mesg_recv(readfd, &mesg)) > 0) { // 将消息内容发送 write(STDOUT_FILENO, mesg.mesg_data, n); } } /* 图4-30 我们的使用消息的server函数*/ /* P55 server.c */ void server(int readfd, int writefd) { FILE *fp; ssize_t n; struct mymesg mesg; mesg.mesg_type = 1; // 读取来自客户的路径名 if ((n = mesg_recv(readfd, &mesg)) == 0) { fprintf(stderr, "pathname messing\n"); exit(1); } mesg.mesg_data[n] = '\0'; // 以空字符结尾的字符串 // 打开客户指定文件 if ((fp = fopen(mesg.mesg_data, "r")) == NULL) { // 打开文件失败 // 构建出错消息 snprintf(mesg.mesg_data + n, sizeof(mesg.mesg_data) - 1, ": can't open, %s\n", strerror(errno)); mesg.mesg_len = strlen(mesg.mesg_data); mesg_send(writefd, &mesg); // 发送出错消息到客户 } else { // 打开文件成功,读出该文件并发送给客户 while (fgets(mesg.mesg_data, MAXMESGDATA, fp) != NULL) { mesg.mesg_len = strlen(mesg.mesg_data); mesg_send(writefd, &mesg); } fclose(fp); // 关闭打开的文件 } mesg.mesg_len = 0; mesg_send(writefd, &mesg); // 发送长度为0的消息表示已到达文件结尾 }
-----------------------------------------------------------------
运行结果如下:
$ ./pipemesg Makefile pipemesg: gcc pipemesg.c -o pipemesg -Wall clean: rm pipemesg