命名管道相关代码及讲解

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <libgen.h>
#include <stdlib.h>

#define FIFO1           ".fifo_chat1"
#define FIFO2           ".fifo_chat2"

int g_stop=0;//创建一个全局变量,以便每个函数都可以使用

void sig_pipe(int signum)
{
        if(SIGPIPE == signum)
        {
                printf("get pipe broken signal and let programe exit\n");
                g_stop=1;
        }

}


int main(int argc,char** argv)
{
        int             mode=0;
        int             fdr_fifo;
        int             fdw_fifo;
        fd_set          rdset;
        char            buf[1024];
        int             rv;


        if(argc!=2)
        {
                printf("Usage :%s [0/1]\n",basename(argv[0]));
                printf("this chat program need run twice,1st time run with [0] and 2nd time with [1]\n");
                return -1;
        }

        mode = atoi(argv[1]);
        if(access(FIFO1,F_OK))//判断是否存在,不存在则使用mkfifo创建一个管道文件;
        {
                printf("FIFO file \"%s\"not exist and create it noe\n,FIFO1");
                mkfifo(FIFO1,0666);
 }

        if(access(FIFO2,F_OK))
        {
                printf("FIFO file \%s\not exist and create it noe\n,FIFO1");
                mkfifo(FIFO2,0666);

        }

        signal(SIGPIPE,sig_pipe);
        if(0 == mode)
        {
                printf("start open '%s' for read and it will blocked untill write endpoint opened...\n",FIFO1);
                if((fdr_fifo=open(FIFO1,O_RDONLY))<0)
                {
                        printf("open fifo[%s] for chat read endpoint failure:%s\n",FIFO1,strerror(errno));
                        return -2;
                }

                printf("start open '%s' for read...\n",FIFO2);
                if((fdw_fifo=open(FIFO2,O_WRONLY))<0)
                {
                        printf("Open fifo[%s] for chat read endpint failure:%s\n",FIFO2,strerror(errno));
                        return -3;

                }
        }

        else
        {
                printf("start open '%s' for write and it will blocked untill read endpoint opened ...\n",FIFO1);

                if((fdw_fifo=open(FIFO1,O_WRONLY))<0)
                {
                        printf("open fifo[%s] for chat write endpoint failure:%s\n",FIFO1,strerror(errno));

                        return -4;
                }
                printf("start open '%s' for read'...\n",FIFO2);
                if((fdr_fifo=open(FIFO2,O_RDONLY))<0)
                {
                        printf("open fifo[%s] for chat readd endpoint failure:%s\n",FIFO2,strerror(errno));
                        return -5;
                }
        }

        printf("start chating with another program now,please input message now:\n");
        while(!g_stop)
        {
                FD_ZERO(&rdset);
                FD_SET(STDIN_FILENO,&rdset);
                FD_SET(fdr_fifo,&rdset);
                rv=select(fdr_fifo+1,&rdset,NULL,NULL,NULL);
                if(rv<=0)
                {
                        printf("Select get timeout or eror:%s\n",strerror(errno));
                        continue;
                }
                if(FD_ISSET(fdr_fifo,&rdset))//监听是否还在集合中,如果是,测返回1,执行if中的语句
                {
                        memset(buf,0,sizeof(buf));
                        rv=read(fdr_fifo,buf,sizeof(buf));
                        if(rv<0)
                        {
                                printf("Another side of FIFO get closed and program will exit now\n");
                                break;
                        }
                        else if(0==rv)//返回0表示另外一端已经断开
                        {
                                printf("Another side of FIFO get closed and program will wxit now\n");
                                break;
                        }

                        printf("<-- %s",buf);

                }
                if(FD_ISSET(STDIN_FILENO,&rdset))
                {
                        memset(buf,0,sizeof(buf));
                        fgets(buf,sizeof(buf),stdin);
                        write(fdw_fifo,buf,strlen(buf));

                }
        }

        return 0;
}

代码

如上

其他函数请自行百度或者查看上一篇文章,应其他文章已经介绍过,在此不再讲解。

命名管道

前面讲到的未命名的管道只能在两个具有亲缘关系的进程之间通信,通过命名管道(Named PiPe)FIFO,不相关的进程也能 交换数据。FIFO不同于管道之处在于它提供一个路径与之关联,以FIFO的文件形式存在于系统中。它在磁盘上有对应的节点,但 没有数据块——换言之,只是拥有一个名字和相应的访问权限,通过mknode()系统调用或者mkfifo()函数来建立的。一旦建 立,任何进程都可以通过文件名将其打开和进行读写,而不局限于父子进程,当然前提是进程对FIFO有适当的访问权。当不再被 进程使用时,FIFO在内存中释放,但磁盘节点仍然存在。 下面这个例程创建了两个掩藏的命名管道文件(.fifo_chat1和.fifo_chat2)在不同的进程间进行双向通信。该程序需要运行两 次(即两个进程),其中进程0(mode=0)从标准输入里读入数据后通过命名管道2(.fifo_chat2)写入数据给进程 1(mode=1);而进程1(mode=1)则从标准输入里读入数据后通过命名管道1(.fifo_chat1)写给进程0,这样使用命名管 道实现了一个进程间聊天的程序。

SIGPIPE

这个信号是很常见的。当往一个写端关闭的管道或socket连接中连续写入数据时会引发SIGPIPE信号,引发SIGPIPE信号的写操作将设置errno为EPIPE。在TCP通信中,当通信的双方中的一方close一个连接时,若另一方接着发数据,根据TCP协议的规定,会收到一个RST响应报文,若再往这个服务器发送数据时,系统会发出一个SIGPIPE信号给进程,告诉进程这个连接已经断开了,不能再写入数据。

 signal函数

void(* signal(int sig,void(* func)(int)))(int);

指定使用sig指定的信号编号处理信号的方法。 参数func指定程序可以处理信号的三种方式之一:

默认处理(SIG_DFL):信号由该特定信号的默认动作处理。
忽略信号(SIG_IGN):忽略信号,即使没有意义,代码执行仍将继续。
函数处理程序:定义一个特定的函数来处理信号。

该程序用的是第三个,接受到该信号之后用一个特定的函数来处理该信号。

access函数

 该函数用来确定文件或者文件的访问 权限。

参数:

pathname:文件目录,当前文件内则可以直接使用文件名

mode:

R_OK 只判断是否有读权限

W_OK 只判断是否有写权限

X_OK 判断是否有执行权限

F_OK 只判断是否存在

定义里面分别对应:

00 只存在

02 写权限

04 读权限

06 读和写权限

select函数

 该函数是用来监视我们需要监视的文件描述符

int maxfdp:集合中所有文件描述符的范围,为所有文件描述符的最大值加1。
fd_set *readfds:要进行监视的读文件集。
fd_set *writefds :要进行监视的写文件集。
fd_set errorfds:用于监视异常数据。
struct timeval
 timeout:select的超时时间,它可以使select处于三种状态:
第一,若将NULL以形参传入,即不传入时间结构,就是 将select置于阻塞状态,一定等到监视文件描述符集合中某个文件描述符发生变化为止;
第二,若将时间值设为0秒0毫秒,就变成一个纯粹的非阻塞函数, 不管文件描述符是否有变化,都立刻返回继续执行,文件无变化返回0,有变化返回一个正值;
第三,timeout的值大于0,这就是等待的超时时间,即 select在timeout时间内阻塞,超时时间之内有事件到来就返回了,否则在超时后不管怎样一定返回

其文件描述字的使用规则如下

fd_set fdset要在前面定义一个该类型的文件描述符

- FD_ZERO(fd_set *fdset);将指定的文件描述符集清空,在对文件描述符集合进行设置前,必须对其进行初始 化,如果不清空,由于在系统分配内存空间后,通常并不作清空处理,所以结果是不可知的。
- FD_SET(fd_set *fdset);用于在文件描述符集合中增加一个新的文件描述符。
- FD_CLR(fd_set *fdset);用于在文件描述符集合中删除一个文件描述符。
- FD_ISSET(int fd,fd_set *fdset);用于测试指定的文件描述符是否在该集合中。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值