浅谈Linux内核管道相关系统手册接口
  tfcxGVdVgiD0 2023年12月05日 30 0

一、管道文件的创建接口mkfifo

1.1在命令行创建一个管道文件

浅谈Linux内核管道相关系统手册接口_mkfifo

这个是用来创建有名管道。一般这么使用,mkfifo +有名管道的名称

浅谈Linux内核管道相关系统手册接口_open_02

指令:mkfifo myfifo

p为管道文件的文件标识符。

1.2在代码中创建管道文件

需要包含头文件

#include<sys/types.h>

#include<sys/stat.h>

浅谈Linux内核管道相关系统手册接口_write_03

使用说明:

mkfifo() 制作一个 FIFO 特殊文件,文件名为 pathname,mode 指定 FIFO 的权限。 它在创建文件的权限为 (mode & ~umask)。

      FIFO 特殊文件与管道类似,只是创建方式不同。  FIFO 特殊文件不是一个匿名通信通道,而是通过调用 mkfifo() 进入文件系统。

      一旦以这种方式创建了先进先出特殊文件,任何进程都可以打开它进行读取或写入,就像普通文件一样。与普通文件相同。 不过,在对其进行任何输入或输出操作之前,必须同时在两端打开文件。

      对其进行任何输入或输出操作。 为读取而打开 FIFO 通常会阻塞,直到其他进程写入数据。

pathname

pathname是char*类型的字符指针,pathname的意义就是指定一个唯一的路径。该路径为有名管道的创建路径。

mode

类型为mode_t 在头文件<sys/stat.h>中被定义,mode_t的取值有哪些

  • S_IRUSR:所有者读取权限(Owner Read)
  • S_IWUSR:所有者写入权限(Owner Write)
  • S_IXUSR:所有者执行权限(Owner Execute)
  • S_IRGRP:组成员读取权限(Group Read)
  • S_IROTH:其他用户读取权限(Others Read)
  • S_IWOTH:其他用户写入权限(Others Write)
  • S_IXOTH:其他用户执行权限(Others Execute)
  • S_IWGRP:组成员写入权限(Group Write)
  • S_IXGRP:组成员执行权限(Group Execute)

O_RDONLY

以只读方式打开文件

O_RDWR

以可读写方式打开文件

O_WRONLY

以只写方式打开文件

匿名管道是一种文件,可以调用read、write和close等操作文件的接口来操作管道。另一方面管道又不是一种普通的文件,它属于一种独特的文件系统:pipefs。管道的本质是内核维护了一块缓冲区与管道文件相关联,对管道文件的操作,被内核转换成对这块缓冲区内存的操作。下面我们来看一下如何使用管道。

浅谈Linux内核管道相关系统手册接口_read_04

pipe这个系统接口来自POSIX通信标准手册,需要如下头文件和系统调用

#include <unistd.h>
int pipe(int fildes[2]);

如果成功,则返回值是0,如果失败,则返回值是-1,并且设置errno。

首先自己得创建一个数组pipefd。成功调用pipe函数之后,会返回两个打开的文件描述符,一个是管道的读取端描述符pipefd[0],另一个是管道的写入端描述符pipefd[1]。管道没有文件名与之关联,因此程序没有选择,只能通过文件描述符来访问管道,只有那些能看到这两个文件描述符的进程才能够使用管道那么谁能看到进程打开的文件描述符呢?只有该进程及该进程的子孙进程才能看到。这就限制了管道的使用范围



二、打开文件open系统接口

浅谈Linux内核管道相关系统手册接口_mkfifo_05

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

//打开文件
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

2.1参数解析

pathname:为文件的地址。操作系统底层是通过文件的路径,唯一的标识找到这个指定的文件。

const char* pathname={"/home/hsq/12_4/demo.txt"};

flags:表示打开这个文件的方法,主要分为以下三种。

浅谈Linux内核管道相关系统手册接口_read_06

mode:如果是新建的文件,那么mode可以指定文件的读写执行的权限。

2.2返回值解析

浅谈Linux内核管道相关系统手册接口_open_07

通过手册可知,如果打开或者创建成功会返回一个文件描述符来标识这个被打开的文件。如果打开或者创建失败就会返回-1,并且错误码被设置。

所以一般我们读文件的代码如下:

#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<iostream>


using namespace std;

int main()
{
    //已只读的方式
    int fd=open("demo.txt",O_RDONLY);
    // //已只写的方式
    // int fd=open("demo.txt",O_WRONLY);
    // //已读和写的方式
    // int fd=open("demo.txt",O_RDWR);

    //返回值错误的处理
    if(fd==-1)
    {
        perror("open fail");
        exit(2);
    }
    else
    {
        cout<<"open success,my fd :"<<fd<<endl;
    }


    return 0;
}

已仅读的方式打开了当前目录下的文件,并返回给我他的文件描述符,fd=3。

浅谈Linux内核管道相关系统手册接口_管道文件_08

2.3谈谈文件描述符

返回值参数解析中,调用系统接口,如果创建或者打开成功就会返回文件描述符,那么为什么给我返回的是3呢。

这里一起探讨一下文件描述符,为什么不返回1或者0,这里得引入Linux系统对文件的管理。

  • 我们知道在Linux系统中一切皆可以看成是文件,文件又可分为:普通文件、目录文件、链接文件和设备文件。在操作这些所谓的文件的时候,我们每操作一次就找一次名字,这会耗费大量的时间和效率。所以Linux中规定每一个文件对应一个索引,这样要操作文件的时候,我们直接找到索引就可以对其进行操作了。
  • 文件描述符(file descriptor)就是内核为了高效管理这些已经被打开的文件所创建的索引,其是一个非负整数(通常是小整数),用于指代被打开的文件,所有执行I/O操作的系统调用都通过文件描述符来实现。同时还规定系统刚刚启动的时候,0是标准输入,1是标准输出,2是标准错误。这意味着如果此时去打开一个新的文件,它的文件描述符会是3,再打开一个文件文件描述符就是4......
  • Linux内核对所有打开的文件有一个文件描述符表格,里面存储了每个文件描述符作为索引与一个打开文件相对应的关系,简单理解就是下图这样一个数组,文件描述符(索引)就是文件描述符表这个数组的下标,数组的内容就是指向一个个打开的文件的指针。

浅谈Linux内核管道相关系统手册接口_read_09

0:标准输入(stdin)

1:标准输出(stdout)

2:标准错误(error)

三、读管道文件read系统接口

浅谈Linux内核管道相关系统手册接口_read_10

3.1参数解析

#include <unistd.h>

ssize_t read(int fd, void *buf, size_t count);

fd:read这个系统接口,首先read的对象肯定文件,如何找到文件,怎么去索引呢。肯定是借助Linux系统提供的文件描述符表格,那么意味着得拿到fd,所以第一个参数就是fd。


buf:Linux系统中的read接口,是面向字节流的设计方式。那么从文件中读出来的是通过字节流放到buf中,根据文件传递的数据类型,在buf的类型设计的时候为了提高read接口的泛型能力,设计为void* ,那么可以接收char*/int*等类型的数据。 通过前面的描述理解,buf是被设计为输出型参数。来获取文件的数据。

浅谈Linux内核管道相关系统手册接口_write_11

count:count表示这个buf的长度大小。通常用sizeof(buf)

char buffer[1024] = {0};
int x = read(fd, buffer, sizeof(buffer));


3.2返回值解析

浅谈Linux内核管道相关系统手册接口_mkfifo_12

解析如下:

如果read成功,那么返回读取的字节个数。如果有数据那么肯定会大于0。如果写端没有写数据,那么读端调用read,获取不到字节,那么返回值被设置为0。通常此时应该结束读端进程。另外,如果调用read接口,出现程序异常,那么返回值为-1,系统错误码被设置。

while (true)
{
  char buffer[1024] = {0};
  int x = read(fd, buffer, sizeof(buffer));
  if (x > 0)
  {
    buffer[x] = 0;
    cout << "client say# " << buffer << endl;
  }
  else if (x == 0)
  {
    log(Debug, "client quit, me too!, error string: %s, error code: %d", strerror(errno), errno);
    break;
  }
  else
    break;
}


四、写管道文件write系统接口

4.1参数解析

浅谈Linux内核管道相关系统手册接口_open_13

#include <unistd.h>

ssize_t write(int fd, const void *buf, size_t count);

fd:这个现在是老生常谈,fd是我们写入文件的文件描述符。这个唯一标识写入文件。

buf:这个和read接口的buf功能差不多,但是这个被设计成输入性参数,也就是buf数组我们得提前填充数据,调用系统接口就可以将buf中的数据写进文件的缓冲区。

string line;
getline(cin, line);
write(fd, line.c_str(), line.size());

count:为当前buf数组的大小,一般这么来编写代码sizeof(buf)/buf.size()。这样可以保证传输的数据的原子性。


4.2返回值解析

浅谈Linux内核管道相关系统手册接口_open_14

首先来看一下返回值的类型,ssize_t在底层是通过typedef进行定义的int类型。所以通过手册可以看出来,返回的是写入的字节个数。如果写入错误,返回值为-1,错误码被更新。

while(true)
{
  cout << "Please Enter@ ";
  getline(cin, line);

  write(fd, line.c_str(), line.size());
}

一般得,我们对write接口的返回值不进行错误处理。

五、关闭文件close系统接口

浅谈Linux内核管道相关系统手册接口_read_15

#include <unistd.h>

int close(int fd);

5.1参数解析

fd:关闭文件的文件描述符。

5.2返回值解析

一般不进行返回值处理。如果fd输入正确,一般close是正常。底层是对fd对应文件的引用计数这个数据--,当引用计数为0,那么这个文件才正式的被关闭。

close(fd);

六、自销毁有名管道文件unlink

浅谈Linux内核管道相关系统手册接口_write_16

#include <unistd.h>

int unlink(const char *pathname);

6.1参数解析

pathname:文件的系统路径。最好是用绝对路径。

6.2返回值解析

浅谈Linux内核管道相关系统手册接口_mkfifo_17

如果管道文件销毁成功,那么将返回0,如果错误那么返回-1,错误码被设置。

int m = unlink(FIFO_FILE);
if (m == -1)
{
  perror("unlink");
  exit(FIFO_DELETE_ERR);
}


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年12月05日 0

暂无评论

tfcxGVdVgiD0