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

        例子:无亲缘关系的客户与服务器(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

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