管道通信——FIFO的代码实现

一、用到的函数
umask
        linux中的 umask 函数主要用于:在创建新文件或目录时 屏蔽掉新文件或目录不应有的访问允许权限。
        文件的访问允许权限共有9种,分别是:r w x r w x r w x(它们分别代表:用户读 用户写 用户执行 组读 组写 组执行 其它读 其它写 其它执行)
        其实这个函数的作用,就是设置允许当前进程创建文件或者目录最大可操作的权限,比如这里设置为0,它的意思就是0取反再创建文件时权限相与,也就是:(~0) &            mode 等于八进制的值0777 & mode了,这样就是给后面的代码调用函数mkdir给出最大的权限,避免了创建目录或文件的权限不确定性
第一位代表了一项特别的安全特性,叫作粘着位(sticky bit),后面的3位表示文件或目录对应的umask八进制值。要理解umask是怎么工作的,得先理解八进制模式的安全性设置。
八进制模式的安全性设置先获取这3个rwx权限的值,然后将其转换成3位二进制值,用一个八进制值来表示。在这个二进制表示中,每个位置代表一个二进制位。因此,如果读权限是唯一置位的权限,权限值就是r--,转换成二进制值就是100,代表的八进制值是4。下表列出了可
能会遇到的组合。
 

S_IFIFO|0666 
        S_IFIFO|0666指明创建有名管道且存取权限为0666,即创建者/其同组用户/其他用户均可读可写

mknod(FIFO_FILE,S_IFIFO|0666,0);
函数mknod参数中path为创建的命名管道的全路径名:mod为创建的命名管道的模式,指明其存取权限;dev为设备值,该值取决于⽂件创建的种类,它只在创建设备⽂件时才会⽤到。这个函数调⽤成功都返回0,失败返回-1

perror
        C 库函数 void perror(const char *str) 把一个描述性错误消息输出到标准错误 stderr。首先输出字符串         str,后跟一个冒号,然后是一个空格
        str -- 这是 C 字符串,包含了一个自定义消息,将显示在原本的错误消息之前
        该函数不返回任何值

exit是一个函数,进程退出时会有一个值,exit函数的参数就是指明进程退出的返回值,操作系统根据这个值来判断是否是正常退出。比如说:
exit(1)是异常退出,比如你的代码在出现不应该出现的分枝,要求终止程序的时候就用exit(1)
exit(0)是正常退出,就是你认为代码一切正常的时候的退出

open
open函数属于Linux中系统IO,用于“打开”文件,代码打开一个文件意味着获得了这个文件的访问句柄。
int fd = open(参数1,参数2,参数3);
int fd = open(const char *pathname,int flags,mode_t mode);
1.句柄(file descriptor 简称fd)
首先每个文件都属于自己的句柄,例如标准输入是0,标准输出是1,标准出错是2。
每打开一个文件就会返回句柄来操作这个文件,一般是从3开始,然后4,5,6一直下去。
close(fd)之后句柄就返回给系统,例如打开一个文件后fd是3,close之后再打开另外一个文件也还是3,但代表的文件不一样了。
2.使用open前需要先包含头文件
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
3.参数1(pathname)
即将要打开的文件路径,例如:“a.txt”当前目录下的a.txt文件
4.参数2(flags)
flags分为两类:主类,副类
主类:O_RDONLY 以只读方式打开   /   O_WRONLY 以只写方式打开   /O_RDWR 以可读可写方式打开
三这是互斥的
副类:
O_CREAT 如果文件不存在则创建该文件
O_EXCL 如果使用O_CREAT选项且文件存在,则返回错误消息
O_NOCTTY 如果文件为终端,那么终端不可以调用open系统调用的那个进程的控制终端
O_TRUNC 如果文件已经存在泽删除文件中原有数据
O_APPEND 以追加的方式打开
主副可以配合使用,例如:O_RDWR|O_CREAT|O_TRUNC
5.参数3(mode)
mode:如果文件被新建,指定其权限未mode
mode是八进制权限码,0777表示文件所有者   该文件用户组     其他用户都有可读可写可执行权限

ssize_t
        ssize_t是有符号整型,在32位机器上等同与int,在64位机器上等同与long int

read()
函数定义:ssize_t read(int fd, void * buf, size_t count);
函数说明:read()会把参数fd所指的文件传送count 个字节到buf 指针所指的内存中。
返回值:返回值为实际读取到的字节数, 如果返回0, 表示已到达文件尾或是无可读取的数据。若参数count 为0, 则read()不会有作用并返回0。
注意:read时fd中的数据如果小于要读取的数据,就会引起阻塞。

fflush
在使用多个输出函数连续进行多次输出时,有可能发现输出错误。因为下一个数据在上一个数据还没输出完毕,还在输出缓冲区中时,下一个printf就把另一个数据加入输出缓冲区,结果冲掉了原来的数据,出现输出错误。 在 printf();后加上fflush(stdout); 强制马上输出,避免错误

close (fd)
每打开一个文件就会返回句柄来操作这个文件,一般是从3开始,然后4,5,6一直下去。
close(fd)之后句柄就返回给系统,例如打开一个文件后fd是3,close之后再打开另外一个文件也还是3,但代表的文件不一样了

write()
函数定义:ssize_t write (int fd, const void * buf, size_t count);
函数说明:write()会把参数buf所指的内存写入count个字节到参数放到所指的文件内。
返回值:如果顺利write()会返回实际写入的字节数。当有错误发生时则返回-1,错误代码存入errno中

 
二、代码实现
read端代码
 1 #include<stdlib.h>
 2 #include<stdio.h>
 3 #include<sys/types.h>
 4 #include<sys/stat.h>
 5 #include<fcntl.h>
 6 #include<errno.h>
 7 #define PATH "./fifo"
 8 #define SIZE 128
 9 int main()
10 {
11 umask(0);
12 if (mkfifo (PATH,0666|S_IFIFO) == -1)
13 {
14 perror ("mkefifo error");
15 exit(0);
16 }
17 int fd = open (PATH,O_RDONLY);
18 if (fd<0)
19 {
20   printf("open fd is error\n");
21   return 0;
22 }
23   
24 char Buf[SIZE];
25 while(1){
26 ssize_t s = read(fd,Buf,sizeof(Buf));
27 if (s<0)
28 {
29   perror("read error");
30   exit(1);
31 }
32 else if (s == 0)
33 {
34   printf("client quit! i shoud quit!\n");
35   break;
36 }
37 else
38 {
39   Buf[s] = '\0';
40   printf("client# %s ",Buf);
41   fflush(stdout);
42 }
43 }
44 close (fd);
45 return 3;
46 }

 


write端代码
 1 #include<stdlib.h>
 2 #include<stdio.h>
 3 #include<unistd.h>
 4 #include<sys/types.h>
 5 #include<sys/stat.h>
 6 #include<string.h>
 7 #include<errno.h>
 8 #include<fcntl.h>
 9   
10 #define PATH "./fifo"
11 #define SIZE 128
12 int main()
13 {
14 int fd = open(PATH,O_WRONLY);
15 if (fd < 0)
16 {
17   perror("open error");
18   exit(0);
19 }
20   
21 char Buf[SIZE];
22 while(1)
23 {
24   printf("please Enter#:");
25   fflush(stdout);
26   ssize_t s = read(0,Buf,sizeof(Buf));
27   if (s<0)
28   {
29    perror("read is failed");
30    exit(1);
31   }
32   else if(s==0)
33   {
34    printf("read is closed!");
35    return 1;
36   }
37   else{
38    Buf[s]= '\0';
39    write(fd,Buf,strlen(Buf));
40   }
41 }
42 return 0;
43 }

三、实例展示

write端
read端
四、存在的问题
数据溢出了怎么办?
当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
这个过程用到了fflush函数。
在 printf();后加上fflush(stdout); 强制马上输出,避免错误
 
posted @ 2019-11-01 01:40  chuyaoxin  阅读(1017)  评论(0编辑  收藏  举报