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

        《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

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