例子:无亲缘关系的客户与服务器(FIFO)
-----------------------------------------------
《UNIX网络编程:卷2》P43:图4-16 独立服务器程序
server_main.c文件内容如下:
/* P43 server_main.c */ #include "fifo.h" void server(int readfd, int writefd); int main(int argc, char *argv[]) { int readfd, writefd; // 创建两个管道 if ((mkfifo(FIFO1, FILE_MODE) < 0) && (errno != EEXIST)) { fprintf(stderr, "can't create %s: %s\n", FIFO1, strerror(errno)); exit(1); } if ((mkfifo(FIFO2, FILE_MODE) < 0) && (errno != EEXIST)) { unlink(FIFO1); fprintf(stderr, "can't create %s: %s\n", FIFO2, strerror(errno)); exit(1); } // 打开FIFO1用于读 if ((readfd = open(FIFO1, O_RDONLY, 0)) < 0) { fprintf(stderr, "open %s error: %s\n", FIFO1, strerror(errno)); } // 打开FIFO2用于写 if ((writefd = open(FIFO2, O_WRONLY, 0)) < 0) { fprintf(stderr, "open %s error: %s\n", FIFO2, strerror(errno)); } server(readfd, writefd); exit(0); } /* 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); } }
由服务器创建FIFO。
-----------------------------------------------
《UNIX网络编程:卷2》P43:图4-19 客户程序和服务器程序都包含的fifo.h头文件
fifo.h文件内容如下:
/* P43 fifo.h */ #ifndef FIFO_H__ #define FIFO_H__ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <sys/stat.h> #include <sys/wait.h> #define MAXLINE 1024 // 用户读、用户写、组成员读和其他用户读,这些权限会被当前进程的文件模式创建掩码修正 #define FILE_MODE(S_IRUSR | S_IWUSR| S_IRGRP | S_IROTH) #define FIFO1"/tmp/fifo.1" #define FIFO2"/tmp/fifo.2" #endif
-----------------------------------------------
《UNIX网络编程:卷2》P44:图4-20 独立客户程序
client_main.c文件内容如下:
/* P44 client_main.c */ #include "fifo.h" void client(int readfd, int writefd); int main(int argc, char *argv[]) { int readfd, writefd; // 打开FIFO1用于写 if ((writefd = open(FIFO1, O_WRONLY, 0)) < 0) { fprintf(stderr, "open %s error: %s\n", FIFO1, strerror(errno)); } // 打开FIFO2用于读 if ((readfd = open(FIFO2, O_RDONLY, 0)) < 0) { fprintf(stderr, "open %s error: %s\n", FIFO2, strerror(errno)); } client(readfd, writefd); // 关闭文件 close(readfd); close(writefd); // 删除文件 unlink(FIFO1); unlink(FIFO2); 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); }
注意,最后删除所用FIFO的是客户而不是服务器,因为对这些FIFO执行最终操作的是客户。
-----------------------------------------------
Makefile文件内容如下:
server_main: gcc server_main.c -o server_main -Wall client_main: gcc client_main.c -o client_main -Wall clean: rm server_main client_main
-----------------------------------------------
编译并运行程序:
$ make server_main client_main 编译程序 gcc server_main.c -o server_main -Wall gcc client_main.c -o client_main -Wall $ ./server_main & 后台启动服务器 [1] 3782 $ ./client_main 启动客户 Makefile 一个普通文件文件 server_main: gcc server_main.c -o server_main -Wall client_main: gcc client_main.c -o client_main -Wall clean: rm server_main client_main [1]+ 完成 ./server_main