利用共享内存,有名管道,select实现两个用户之间的自由对话。
原理:send1.c send2.c recv1.c recv2.c 12.fifo 21.fifo
send1.c(send2.c) 为用户1(2)的发送端,负责从标准输入读入数据传递给用户2(1)和接收用户2(1)发送的数据并传递给用户1(2)的打印端recv1.c(recv2.c)打印输出。
recv1.c(recv2.c) 为用户1(2)的打印端,将用户1(2)接收到的数据打印出来。
模式关系图:
需要用select函数来轮询检测标准输入和管道的读端,保证实时性。
send1.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct my_mem
{
int m_lock;
int m_unshow;
char m_buf[128];
}mem_t,*pmem_t;
void lock(pmem_t pm)
{
while(pm->m_lock==0)
{
sleep(1);
}
pm->m_lock=0;
}
void unlock(pmem_t pm)
{
pm->m_lock=1;
}
int main(int argc,char *argv[])
{
int shmid;
char line[128];
int fd_s,fd_r;
int ret;
//open fifo 12.fifo 21.fifo
fd_s=open("./12.fifo",O_WRONLY);
fd_r=open("./21.fifo",O_RDONLY);
printf("fd_s:%d,fd_r:%d\n",fd_s,fd_r);
//获取共享内存
shmid=shmget((key_t)1234,sizeof(mem_t),IPC_CREAT);
if(shmid==-1)
{
perror("shmget");
exit(1);
}
pmem_t pm=shmat(shmid,NULL,0);
pm->m_lock=1;
pm->m_unshow=0;
//select轮询检测标准输入和管道读端
fd_set rds;
struct timeval tm;
while(1)
{
FD_ZERO(&rds);
FD_SET(0,&rds);
FD_SET(fd_r,&rds);
tm.tv_usec=0;
tm.tv_sec=5;
ret=select(1024,&rds,NULL,NULL,&tm);
if(ret==0)
{
continue;
}
else if(ret>0)
{
if(FD_ISSET(0,&rds))
{
memset(line,0,128);
read(0,line,127);
write(fd_s,line,strlen(line));
}
if(FD_ISSET(fd_r,&rds))
{
memset(line,0,128);
read(fd_r,line,127);
lock(pm);
while(pm->m_unshow==1)
{
unlock(pm) ;
sleep(1);
lock(pm);
}
strcpy(pm->m_buf,line);
pm->m_unshow=1;
unlock(pm);
}
}
}
close(fd_s);
close(fd_r);//关闭管道
shmdt(pm);//共享内存段与进程空间分离
shmctl(shmid,IPC_RMID,NULL);//删除共享内存段
return 0;
}
recv1.c
#include
#include
#include
#include
#include
#include
typedef struct my_mem
{
int m_lock;
int m_unshow;
char m_buf[128];
}mem_t,*pmem_t;
void lock(pmem_t pm)
{
while(pm->m_lock==0)
{
sleep(1);
}
pm->m_lock=0;
}
void unlock(pmem_t pm)
{
pm->m_lock=1;
}
int main(int argc,char *argv[])
{
int shmid;
shmid=shmget((key_t)1234,sizeof(mem_t),IPC_CREAT);
if(shmid==-1)
{
perror("shmget");
exit(1);
}
pmem_t pm=shmat(shmid,NULL,0);
while(1)
{
lock(pm);
while(pm->m_unshow==0)
{
unlock(pm);
sleep(1);
lock(pm);
}
printf("from 2:%s\n",pm->m_buf);
pm->m_unshow=0;
unlock(pm);
}
shmdt(pm);
return 0;
}
send2.c
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
typedef struct my_mem
{
int m_lock;
int m_unshow;
char m_buf[128];
}mem_t,*pmem_t;
void lock(pmem_t pm)
{
while(pm->m_lock==0)
{
sleep(1);
}
pm->m_lock=0;
}
void unlock(pmem_t pm)
{
pm->m_lock=1;
}
int main(int argc,char *argv[])
{
int shmid;
char line[128];
int fd_s,fd_r;
int ret;
//open fifo 12.fifo 21.fifo
fd_r=open("./12.fifo",O_RDONLY);
fd_s=open("./21.fifo",O_WRONLY);
printf("fd_s:%d,fd_r:%d\n",fd_s,fd_r);
//获取共享内存
shmid=shmget((key_t)5678,sizeof(mem_t),IPC_CREAT);
if(shmid==-1)
{
perror("shmget");
exit(1);
}
pmem_t pm=shmat(shmid,NULL,0);
pm->m_lock=1;
pm->m_unshow=0;
//select
fd_set rds;
struct timeval tm;
while(1)
{
FD_ZERO(&rds);
FD_SET(0,&rds);
FD_SET(fd_r,&rds);
tm.tv_usec=0;
tm.tv_sec=5;
ret=select(1024,&rds,NULL,NULL,&tm);
if(ret==0)
{
continue;
}
else if(ret>0)
{
if(FD_ISSET(0,&rds))
{
memset(line,0,128);
read(0,line,127);
write(fd_s,line,strlen(line));
}
if(FD_ISSET(fd_r,&rds))
{
memset(line,0,128);
read(fd_r,line,127);
lock(pm);
while(pm->m_unshow==1)
{
unlock(pm) ;
sleep(1);
lock(pm);
}
strcpy(pm->m_buf,line);
pm->m_unshow=1;
unlock(pm);
}
}
}
close(fd_s);
close(fd_r);
shmdt(pm);
shmctl(shmid,IPC_RMID,NULL);
return 0;
}
recv2.c
#include
#include
#include
#include
#include
#include
typedef struct my_mem
{
int m_lock;
int m_unshow;
char m_buf[128];
}mem_t,*pmem_t;
void lock(pmem_t pm)
{
while(pm->m_lock==0)
{
sleep(1);
}
pm->m_lock=0;
}
void unlock(pmem_t pm)
{
pm->m_lock=1;
}
int main(int argc,char *argv[])
{
int shmid;
shmid=shmget((key_t)5678,sizeof(mem_t),IPC_CREAT);
if(shmid==-1)
{
perror("shmget");
exit(1);
}
pmem_t pm=shmat(shmid,NULL,0);
while(1)
{
lock(pm);
while(pm->m_unshow==0)
{
unlock(pm);
sleep(1);
lock(pm);
}
printf("from1:%s\n",pm->m_buf);
pm->m_unshow=0;
unlock(pm);
}
shmdt(pm);
return 0;
}
编译运行四个文件,gcc –g –o send1 send1.c gcc –g–o send2 send2.c gcc –g –o recv1 recv1.c gcc –g –o recv1 recv1.c
运行结果:
这段程序还有待优化,进程退出需要在结构体中添加一个标记,来表明管道是否关闭。可以参考上一篇文章。