Error message here!

Hide Error message here!

忘记密码?

Error message here!

请输入正确邮箱

Hide Error message here!

密码丢失?请输入您的电子邮件地址。您将收到一个重设密码链接。

Error message here!

返回登录

Close

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

笛在月明楼 2019-11-01 01:40:00 阅读数:26 评论数:0 点赞数:0 收藏数:0

一、用到的函数
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端代码
 #include<stdlib.h>
 #include<stdio.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<fcntl.h>
 #include<errno.h>
 #define PATH "./fifo"
 #define SIZE 128
 int main()
 {
 umask();
 if (mkfifo (PATH,|S_IFIFO) == -)
 {
 perror ("mkefifo error");
 exit();
 }
 int fd = open (PATH,O_RDONLY);
 if (fd<)
 {
   printf("open fd is error\n");
   return ;
 }
   
 char Buf[SIZE];
 while(){
 ssize_t s = read(fd,Buf,sizeof(Buf));
 if (s<)
 {
   perror("read error");
   exit();
 }
 else if (s == )
 {
   printf("client quit! i shoud quit!\n");
   break;
 }
 else
 {
   Buf[s] = '\0';
   printf("client# %s ",Buf);
   fflush(stdout);
 }
 }
 close (fd);
 return ;
 }

 


write端代码
 #include<stdlib.h>
 #include<stdio.h>
 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<string.h>
 #include<errno.h>
 #include<fcntl.h>
   
 #define PATH "./fifo"
 #define SIZE 128
 int main()
 {
 int fd = open(PATH,O_WRONLY);
 if (fd < )
 {
   perror("open error");
   exit();
 }
   
 char Buf[SIZE];
 while()
 {
   printf("please Enter#:");
   fflush(stdout);
   ssize_t s = read(,Buf,sizeof(Buf));
   if (s<)
   {
    perror("read is failed");
    exit();
   }
   else if(s==)
   {
    printf("read is closed!");
    return ;
   }
   else{
    Buf[s]= '\0';
    write(fd,Buf,strlen(Buf));
   }
 }
 return ;
 }

三、实例展示

write端
read端
四、存在的问题
数据溢出了怎么办?
当这种情况发生时,随后对管道的write()调用将默认地被阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。
这个过程用到了fflush函数。
在 printf();后加上fflush(stdout); 强制马上输出,避免错误
 
版权声明
本文为[chuyaoxin]所创,转载请带上原文链接,感谢
https://www.cnblogs.com/cyx-b/p/11774863.html