/*
名称:利用有名管道实现进程间通信(聊天小程序)
说明:此程序,是利用有名管道实现进程间的相互通信。
关于有名管道,需要说的是,它是一个特殊的文件,因为它的名字会保存在文件系统中(inode节点,这也是其为什么能在无关进程间通信的原因吧)但是,它的内容并不是在内存中(无名管道的名字和内容都是放在内存中的)。
关于管道的建立,有一点要说明的就是一般来说,我们只需要把管道的打开方式设置成阻塞的(默认)的就可以,但是这个程序中,要把管道设置成非阻塞的(因为你也不知道对方什么时候会发给你,你什么时候会发送消息给对方)。在设置管道非阻塞的时候,需要用到一个新的函数,就是fcntl()(我把它叫做文件控制函数)。它可以把文件描述符所代表的文件流(此处是管道流)设置成非阻塞的。
其次,由于要双向通信,而命名管道一般用于单双工通信,所以需要两个管道。但是比较气人的是,由于种种原因(我也不清楚的原因)在设置打开非阻塞管道是时候,必须先打开读端,再打开写端,再打开写端,否则就会出错。由于这个原因,我们不能同时打开两个文件管道(因为在一个进程中需要以读方式打开一个管道,在以写方式打开一个管道),如果同时打开的话,会出错。为了解决这个问题,我让server首先打开pipe1的读端,然后一直监听是否有消息,如果有消息的话在打开另一个管道写端。这样的话,在运行程序的时候只能先让server程序先运行了。
*/
//server端
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
//初始化函数,用于非阻塞标准输入
int Init()
{
if(-1 == fcntl(0,F_SETFL,O_NONBLOCK))
{
printf("fail to change the std mode.\n");
return -1;
}
}
int main()
{
int pipe_fd1,pipe_fd2;
int read_cou = 0,write_cou = 0;
char read_buf[100];
char write_buf[100];
memset(read_buf,'\0',sizeof(read_buf));
memset(write_buf,'\0',sizeof(write_buf));
//判断管道是否存在,如果不存在就创建有名管道
if(-1 == access("pipe1",F_OK))
{
if(-1 == mkfifo("pipe1",0777))
{
printf("Could not create pipe1\n");
return -1;
}
}
if(-1 == access("pipe2",F_OK))
{
if(-1 == mkfifo("pipe2",0777))
{
printf("Could not create pipe2\n");
return -1;
}
}
//先打开一个管道,此管道用于server读,client写。非阻塞打开
pipe_fd1 = open("pipe1",O_RDONLY | O_NONBLOCK);
Init();
//这个while循环用于检测是否有client提出访问请求(发来信息)
while(1)
{
read_cou = read(pipe_fd1,read_buf,PIPE_BUF); //从管道中读取数据
if(read_cou > 0)
{
printf("receive client:%s\n",read_buf);
pipe_fd2 = open("pipe2",O_WRONLY | O_NONBLOCK); //如果首次提出请求,则打开第二个管道用于server写,client读
break;
}
}
//正式交流信息阶段
while(1)
{
//读出过程
read_cou = read(pipe_fd1,read_buf,PIPE_BUF);
if(read_cou > 0)
{
printf("server receive :%s\n",read_buf);
}
//从标准输入中读取,如果有输入再写入管道
if (gets(write_buf) != NULL)
{
printf("server input:%s.\n",write_buf);
write(pipe_fd2,write_buf,sizeof(write_buf));
}
}
return 0;
}
//client端:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <limits.h>
#include <string.h>
#include <fcntl.h>
//初始化函数,用于非阻塞标准输入
int Init()
{
if(-1 == fcntl(0,F_SETFL,O_NONBLOCK))
{
printf("fail to change the std mode.\n");
return -1;
}
}
int main()
{
int pipe_fd1,pipe_fd2;
int read_cou = 0,write_cou = 0;
char read_buf[100];
char write_buf[100];
memset(read_buf,'\0',sizeof(read_buf));
memset(write_buf,'\0',sizeof(write_buf));
//判断管道是否存在,如果不存在就创建有名管道
if(-1 == access("pipe1",F_OK))
{
if(-1 == mkfifo("pipe1",0777))
{
printf("Could not create pipe1\n");
return -1;
}
}
if(-1 == access("pipe2",F_OK))
{
if(-1 == mkfifo("pipe2",0777))
{
printf("Could not create pipe2\n");
return -1;
}
}
//打开两个管道,其中pipe1用于server读,pipe2用于server写(非阻塞打开)
pipe_fd1 = open("pipe1",O_WRONLY | O_NONBLOCK);
pipe_fd2 = open("pipe2",O_RDONLY | O_NONBLOCK);
Init();
//此循环用于首先向server提出请求,是server打开第二个通信管道
while(1)
{
//写入过程
if (gets(write_buf) != NULL)
{
printf("client input:%s.\n",write_buf);
write(pipe_fd1,write_buf,sizeof(write_buf));
sleep(1);
break;
}
}
//和server正式通信
while(1)
{
//读出过程
read_cou = read(pipe_fd2,read_buf,PIPE_BUF);
if(read_cou > 0)
{
printf("client receive :%s\n",read_buf);
}
//写入过程
if (gets(write_buf) != NULL)
{
//从标准输入中读取,如果有输入再写入管道
printf("client input:%s.\n",write_buf);
write(pipe_fd1,write_buf,sizeof(write_buf));
}
}
return 0;
}