理解代码:
/**
suck 端简单实现
*/
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/select.h>
#include<fcntl.h>//读取方式宏定义
#include<sys/stat.h>//用户权限宏定义
#include<time.h>
int main(){
int i,rfd,wfd,len=0,fd_in;
char str[32];
int flag,stdinflag;
//a file describe set
fd_set write_fd,read_fd;
struct timeval wait_time;
//create and give power
mkfifo("fifo1",S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
mkfifo("fifo2",S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
//这里需要注意打开FIFO读端会产生阻塞,直到它的写端打开
wfd=open("fifo1",O_WRONLY);
rfd=open("fifo2",O_RDONLY);
if(rfd<=0||wfd<=0)
return 0;
printf("suck client!\n");
while(1){
FD_ZERO(&read_fd);//初始化文件描述符集合中的各个文件描述符
FD_SET(rfd,&read_fd);//管道fifo1的读端文件描述符添加到文件描述符集合
FD_SET(fileno(stdin),&read_fd);//将标准输入文件描述符添加到集合
wait_time.tv_sec=5;//设置检测时间
wait_time.tv_usec=0;//应该是微秒的意思
memset(str,0,sizeof(str));
//select检测集合中是否有可读的东西,检测时间为5m,超时或错误则continue
if(i=select(rfd+1,&read_fd,NULL,NULL,&wait_time)<=0)
continue;
//memset检测时会将没有内容的文件描述符去除
//如果rfd即管道内有可读内容则执行
if(FD_ISSET(rfd,&read_fd)){
read(rfd,str,sizeof(str));
printf("===============\n");
printf("message from dog:%s\n",str);
}
//如果键盘有输入
if(FD_ISSET(fileno(stdin),&read_fd)){
printf("==========\n");
fgets(str,sizeof(str),stdin);
len=write(wfd,str,strlen(str));
}
}
close(rfd);
close(wfd);
return 0;
}
/**
dog端简单实现
*/
#include<stdio.h>
#include<string.h>
#include<sys/stat.h>
#include<unistd.h>
#include<fcntl.h>
#include<time.h>
#include<sys/select.h>
int main(){
int i,rfd,wfd,len=0,fd_in;
char str[32];
int flag,stdinflag;
fd_set read_fd,write_fd;
struct timeval wait_time;
mkfifo("fifo1",S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
mkfifo("fifo2",S_IWUSR|S_IRUSR|S_IRGRP|S_IROTH);
rfd=open("fifo1",O_RDONLY);
wfd=open("fifo2",O_WRONLY);
if(rfd<=0||wfd<=0)
return 0;
printf("dog client!\n");
while(1){
FD_ZERO(&read_fd);
FD_SET(rfd,&read_fd);
FD_SET(fileno(stdin),&read_fd);
wait_time.tv_sec=5;
wait_time.tv_usec=0;
memset(str,0,sizeof(str));
if(i=select(wfd+1,&read_fd,NULL,NULL,&wait_time)<=0)
continue;
if(FD_ISSET(rfd,&read_fd)){
read(rfd,str,sizeof(str));
printf("==============\n");
printf("message from suck:%s\n",str);
}
if(FD_ISSET(fileno(stdin),&read_fd)){
printf("===============\n");
fgets(str,sizeof(str),stdin);
len=write(wfd,str,strlen(str));
}
}
close(rfd);
close(wfd);
return 0;
}
运行结果:
总结:需要注意一个地方 ,在两个客户端的代码中有两端需要多理解。
wfd=open("fifo1",O_WRONLY);
rfd=open("fifo2",O_RDONLY);
rfd=open("fifo1",O_RDONLY);
wfd=open("fifo2",O_WRONLY);
在阻塞模式下,FIFO只有在读写端同时打开时才会返回,否则会一直阻塞。所以fifo1和fifo2顺序不能一个在前一个在后,如果一前一后会导致程序1和2都卡在等另外的端口打开。这好像是产生死锁的四个必要条件中的,循环等待条件
- 互斥条件:资源是独占的且排他使用,进程互斥使用资源,即任意时刻一个资源只能给一个进程使用,其他进程若申请一个资源,而该资源被另一进程占有时,则申请者等待直到资源被占有者释放。
- 不可剥夺条件:进程所获得的资源在未使用完毕之前,不被其他进程强行剥夺,而只能由获得该资源的进程资源释放。
- 请求和保持条件:进程每次申请它所需要的一部分资源,在申请新的资源的同时,继续占用已分配到的资源。
- 循环等待条件 在发生死锁时必然存在一个进程等待队列{P1,P2,…,Pn},其中P1等待P2占有的资源,P2等待P3占有的资源,…,Pn等待P1占有的资源,形成一个进程等待环路,环路中每一个进程所占有的资源同时被另一个申请,也就是前一个进程占有后一个进程所深情地资源。
以上给出了导致死锁的四个必要条件,只要系统发生死锁则以上四个条件至少有一个成立。事实上循环等待的成立蕴含了前三个条件的成立,似乎没有必要列出然而考虑这些条件对死锁的预防是有利的,因为可以通过破坏四个条件中的任何一个来预防死锁的发生。
里面主要的函数用法可以自行百度Google,也可参考:https://blog.csdn.net/cstarbl/article/details/7645298