// msg.h
#include <stdio.h>
#include <stdlib.h>
#define PIPE_BUF 100
#define MAXMSGDATA (PIPE_BUF - 2*sizeof(long))
#define MSG_LEN_TYPE_SIZE (sizeof(struct mymsg) - MAXMSGDATA)
#define FIFO1 "./fifo_1"
#define FIFO2 "./fifo_2"
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
struct mymsg
{
long msg_len;
long msg_type;
char msg_data[MAXMSGDATA];
};
ssize_t msg_send(int, struct mymsg*);
ssize_t msg_recv(int, struct mymsg*);
// msg.c
#include "msg.h"
ssize_t msg_send(int fd, struct mymsg *pmsg)
{
return (write(fd, pmsg, MSG_LEN_TYPE_SIZE + pmsg->msg_len));
}
ssize_t msg_recv(int fd, struct mymsg *pmsg)
{
size_t len;
ssize_t n;
if((n = read(fd, pmsg, MSG_LEN_TYPE_SIZE)) == 0)
{
return 0; // end of ile
}
else if(n != MSG_LEN_TYPE_SIZE)
{
perror("read len_type error.\n");
exit(1);
}
if((len = pmsg->msg_len) > 0)
{
if((n = read(fd, pmsg->msg_data, len)) != len)
{
perror("read msg_data error.\n");
exit(1);
}
}
return len;
}
// client.c
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include "msg.h"
void client(int readfd, int writefd)
{
size_t len;
ssize_t n;
struct mymsg msg;
if(fgets(msg.msg_data, MAXMSGDATA, stdin) == NULL)
{
perror("client fgets error.");
exit(1);
}
len = strlen(msg.msg_data);
if(msg.msg_data[len-1] == '\n')
len--;
msg.msg_len = len;
msg.msg_type = 1;
msg_send(writefd, &msg);
while((n = msg_recv(readfd, &msg)) > 0)
write(1, msg.msg_data, n);
}
int main(int argc, char **argv)
{
int readfd, writefd;
writefd = open(FIFO2, O_WRONLY, 0);
readfd = open(FIFO1, O_RDONLY, 0);
client(readfd, writefd);
close(readfd);
close(writefd);
unlink(readfd);
unlink(writefd);
return 0;
}
// server.c
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include "msg.h"
void server(int readfd, int writefd)
{
ssize_t n;
struct mymsg msg;
FILE *fp;
if((n = msg_recv(readfd, &msg)) == 0)
{
perror("read error in server");
exit(1);
}
msg.msg_data[n] = '\0';
if((fp = fopen(msg.msg_data, "r")) == NULL)
{
snprintf(msg.msg_data + n, sizeof(msg.msg_data) - n, ": cannot open %s\n", strerror(errno));
n = strlen(msg.msg_data);
msg_send(writefd, &msg);
}
else
{
while(fgets(msg.msg_data, MAXMSGDATA, fp) != NULL)
{
msg.msg_len = strlen(msg.msg_data);
msg_send(writefd, &msg);
}
fclose(fp);
}
}
int main(int argc, char **argv)
{
int readfd, writefd;
if(mkfifo(FIFO1, FILE_MODE) < 0 && errno != EEXIST)
{
perror("mkfifo 1 error.");
}
if(mkfifo(FIFO2, FILE_MODE) < 0 && errno != EEXIST)
{
perror("mkfifo 2 error.");
unlink(FIFO1);
}
readfd = open(FIFO2, O_RDONLY, 0); //这里和lcient.c中的FIFO2,O_WRONLY对应,且该行需在下边的writefd = open(FIFO1, O_WRONLY, 0);之前。否则server和client将会一直阻塞
if(readfd == -1)
{
printf("raed FIFO2 error\n");
unlink(FIFO1);
unlink(FIFO2);
return -1;
}
writefd = open(FIFO1, O_WRONLY, 0);
if(writefd == -1)
{
printf("write FIFO1 error\n");
unlink(FIFO1);
unlink(FIFO2);
return -1;
}
server(readfd, writefd);
return 0;
}
[test@localhost test]./server
[test@localhost test]./client
text.txt
服务端读取text.txt内容并发送至客户端,客户端输出在屏幕。
一般在使用管道时,信息是以字节流的形式传递的,没有边界。有时候应用希望对所传递的数据加上某种结构。当数据由变长消息构成,并且读出者必须知道这些消息的边界以判定何时已读出单个消息时,这种需求可能发生。一下列出3种常用技巧:
1.内带特殊终止序列:许多Unix应用程序使用换行符来分隔每个消息。写入进程给每个消息添加换行符,读出进程每次读出一行。FTP、SMTp、HTTP、NNTP等使用一个回车符跟一个换行符构成双字符序列来分隔文本记录;
2.显式长度:每个记录前冠以其长度。(如本例)
3.每次连接一个记录:应用通过关闭与其对方的连接来指示一个记录结束。这要求每个记录都需要创建一个新连接。