《unix高级环境编程》高级 I/O——STREAMS(流)

        STREAMS(流)是系统 V 提供的构造内核设备驱动程序和网络协议包的一种通用方法。流在用户进程和设备驱动程序之间提供了一条全双工通路,下面是流在用户进程和设备驱动程序之间的流图:写到流首的数据将顺流而下传送,由设备驱动程序读到的数据则逆流向上传送;


STREAMS 消息

        STREAMS 的所有输入和输出都是基于消息,流首和用户进程使用 read、write、ioctl、getmsg、getpmsg、putmsg 和 putpmsg 交换信息。在流首、各处理模块和设备驱动程序之间,消息可顺流而下,也可逆流而上。

       在用户进程和流首之间,消息由以下几部分组成:消息类型、控制信息和数据;其中控制信息和数据由以下结构指定:

struct strbuf
{
       int maxlen;  /* size of buffer */
       int len;         /* number of bytes currently in buffer */
       char *buf;    /* pointer to buffer */
};
 
        当使用putmsg 或 putpmsg 发送消息时,len 指定缓冲区中数据的字节数;当使用 getmsg 或 getpmsg 接收消息时,maxlen 指定缓冲区长度,而 len 则由内核设置为存放缓冲区的数据量;消息长度允许为0,len 为 -1 时说明没有控制信息和数据。

       在我们所使用的函数(read,write,getmsg,getpmsg,putmsg 和 putpmsg)中,只涉及三种消息类型,他们是:

  1. M_DATA(I/O 的用户数据);
  2. M_PROTO(协议控制信息);
  3. M_PCPROTO(高优先级协议控制信息);

       流中的消息都有一个排队优先级:

  1. 高优先级消息(最高优先级);
  2. 优先级波段消息;
  3. 普通消息(最低优先级);

        普通信消息是优先级波段为 0 的消息,优先级波段可在 1~255 之间,波段愈高,优先级也愈高,在任何时刻流首只有一个高优先级消息排队,若在流首读队列已有一个高优先级消息,则另外的高优先级消息会被丢弃。

putmsg 和 putpmsg 函数

         putmsg 和 putpmsg 函数用于 STREAMS 消息写至流中,这两个函数的区别是后者允许对消息指定一个优先级波段。

/* 流 */
/*
 * 函数功能:将STREAMS消息写至流;
 * 返回值:若成功则返回0,若出错则返回-1;
 * 函数原型:
 */
#include <stropts.h>
int putmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int flags);
int putpmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int band, int flags);
/*
 * 说明:
 * 对流使用write函数等价于不带任何控制信息、flags为0的putmsg函数;
 * 这两函数可以产生三种不同优先级的消息:普通、优先级波段和高优先级;
 */

STREAMS 的 ioctl 操作

        ioctl 函数如下:

/* Perform the I/O control operation specified by REQUEST on FD.
   One argument may follow; its presence and type depend on REQUEST.
   Return value depends on REQUEST.  Usually -1 indicates error.  */
 int ioctl (int __fd, unsigned long int __request, ...) ;
        ioctl 的第二个参数request说明执行哪一个操作。所有request都以I_开始。第三个参数的作用与request有关,有时它是一个整型值,有时它是指向一个整型或一个数据结构的指针。

/*
 * 函数功能:判断描述符是否引入一个流;
 * 返回值:若为STREAMS设备则返回1,否则返回0;
 * 函数原型:
 */
#include <stropts.h>
int isastream(int filedes);
/*
 * 说明:
 * 该函数是通过ioctl函数来进行的,可有如下实现:
 */
#include <stropts.h>
#include <unistd.h>
int isastream(int fd)
{
    return(ioctl(fd, I_CANPUT, 0) != -1);
}

写模式

        可以使用两个 ioctl 命令取得和设置一个流的写模式,如果将 request 设置为 I_GWPORT,第三个参数设置为指向一个整型变量的指针,则该流的当前写模式在该整型变量中返回。如果将 request 设置为 I_SWPORT,第三个参数是一个整型值,则其值成为该流新的写模式,我们可以先获取当前写模式值,然后修改它,则进行设置。目前只定义了两个写模式值。

  1. SNDZERO:对管道和 FIFO 的0长度 write 会造成顺流传送一个0长度消息。按系统默认,0长度写不发送消息。
  2. SNDPIPE:在流上已出错后,若调用 write 和 putmsg,则向调用进程发送 SIGPIPE 信息。

读模式

        读STREAMS设备有两个潜在的问题:

  1. 如果读到流中消息的记录边界将会怎样?
  2. 如果调用 read,而流中下一个消息由控制信息又将如何?
        对第一种情况的默认处理模式称为字节流模式。read 从流中取数据直至满足了所要求的字节数,或者已经不再有数据。在这种模式中,忽略流中消息的边界。第二种情况的默认处理是,read 出错返回。可以改变这两种默认处理模式。
        调用 ioctl 时,若将 request 设置成 I_GRDOPT,第三个参数又是指向一个整型单元的指针,则对该流的当前读模式在该整型单元中返回。如果将 request 设置为 I_SRDOPT,第三个参数是整型值,则将该流的读模式设置为该值。读模式可由下列三个常量指定:
  1. RNORM:普通,字节流模式,如上述这是默认模式。
  2. RMSGN:消息不丢弃模式,read从流中取数据知道读到所要求的字节数,或者到达消息边界。如果某次read只用了消息的一部分,则其余部分仍留在流中,以供下一次读。
  3. RMSGD:消息丢弃模式,这与不丢弃模式的区别是,如果某次只用了消息的一部分,则余下部分就被丢弃,不再使用。

         在读模式中还可指定另外三个变量,以便设置在读到流中包含协议控制信息的消息时read的处理方法:任一时刻,智能设置一种消息读模式和一种协议读模式,默认读模式是:(RNORM | RPROTNORM)。

  1. RPROTNORM:协议-普通模式。read 出错返回,errno 设置为 EBADMSG。这是默认模式。
  2. RPROTDAT:协议-数据模式。read 将控制部分作为数据返回给调用者。
  3. RPROTDIS:协议-丢弃模式。read 丢弃消息中的控制信息。但是返回消息中的数据。

getmsg 和 getpmsg 函数


/*
 * 函数功能:将从流读STREAMS消息;
 * 返回值:若成功则返回非负值,若出错则返回-1;
 * 函数原型:
 */
#include <stropts.h>
int getmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int *flagptr);
int getpmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int *bandptr, int *flagptr);
/*
 * 说明:
 * 如果flagptr指向的整型单元的值是0,则getmsg返回流首读队列中的下一个消息;
 * 如果下一个消息是最高优先级消息,则在返回时,flagptr所指向的整型单元设置为RS_HIPRI;
 * 如果只希望接收高优先级消息,则在调用getmsg之前必须将flagptr所指向的整型单元设置为RS_HIPRI;
 * getmsg可以设置待接收消息的优先级波段;
 */


参考资料:

《UNIX高级环境编程》

本书全面介绍了UNIX系统的程序设计界面—系统调用界面和标准C库提供的许多函数。 本书的前15章着重于理论知识的阐述,主要内容包括UNIX文件和目录、进程环境、进程控制、 进程间通信以及各种I/O。在此基础上,分别按章介绍了多个应用实例,包括如何创建数据库函数库, PostScript 打印机驱动程序,调制解调器拨号器及在伪终端上运行其他程序的程序等。 本书内容丰富权威, 概念清晰精辟,一直以来被誉为UNIX编程的“圣经”,对于所有UNIX程序员—无论是初学者还是专家级人士 —都是一本无价的参考书籍。 目 录 译者序 译者简介 前言 第1章 UNIX基础知识 1 1.1 引言 1 1.2 登录 1 1.2.1 登录名 1 1.2.2 shell 1 1.3 文件和目录 2 1.3.1 文件系统 2 1.3.2 文件名 2 1.3.3 路径名 2 1.3.4 工作目录 4 1.3.5 起始目录 4 1.4 输入和输出 5 1.4.1 文件描述符 5 1.4.2 标准输入、标准输出和标准 出错 5 1.4.3 不用缓存的I/O 5 1.4.4 标准I/O 6 1.5 程序和进程 7 1.5.1 程序 7 1.5.2 进程和进程ID 7 1.5.3 进程控制 7 1.6 ANSI C 9 1.6.1 函数原型 9 1.6.2 类属指针 9 1.6.3 原始系统数据类型 10 1.7 出错处理 10 1.8 用户标识 11 1.8.1 用户ID 11 1.8.2 组ID 12 1.8.3 添加组ID 12 1.9 信号 12 1.10 UNIX时间值 14 1.11 系统调用和库函数 14 1.12 小结 16 习题 16 第2章 UNIX标准化及实现 17 2.1 引言 17 2.2 UNIX标准化 17 2.2.1 ANSI C 17 2.2.2 IEEE POSIX 18 2.2.3 X/Open XPG3 19 2.2.4 FIPS 19 2.3 UNIX实现 19 2.3.1 SVR4 20 2.3.2 4.3+BSD 20 2.4 标准和实现的关系 21 2.5 限制 21 2.5.1 ANSI C限制 22 2.5.2 POSIX限制 22 2.5.3 XPG3限制 24 2.5.4 sysconf、pathconf 和fpathconf 函数 24 2.5.5 FIPS 151-1要求 28 2.5.6 限制总结 28 2.5.7 未确定的运行时间限制 29 2.6 功能测试宏 32 2.7 基本系统数据类型 32 2.8 标准之间的冲突 33 2.9 小结 34 习题 34 第3章 文件I/O 35 3.1 引言 35 3.2 文件描述符 35 3.3 open函数 35 3.4 creat函数 37 3.5 close函数 37 3.6 lseek函数 38 3.7 read函数 40 3.8 write函数 41 3.9 I/O的效率 41 3.10 文件共享 42 3.11 原子操作 45 3.11.1 添加至一个文件 45 3.11.2 创建一个文件 45 3.12 dup和dup2函数 46 3.13 fcntl函数 47 3.14 ioctl函数 50 3.15 /dev/fd 51 3.16 小结 52 习题 52 第4章 文件和目录 54 4.1 引言 54 4.2 stat, fstat和lstat函数 54 4.3 文件类型 55 4.4 设置-用户-ID和设置-组-ID 57 4.5 文件存取许可权 58 4.6 新文件和目录的所有权 60 4.7 access函数 60 4.8 umask函数 62 4.9 chmod和fchmod函数 63 4.10 粘住位 65 4.11 chown, fchown和 lchown函数 66 4.12 文件长度 67 4.13 文件截短 68 4.14 文件系统 69 4.15 link, unlink, remove和rename 函数 71 4.16 符号连接 73 4.17 symlink 和readlink函数 76 4.18 文件的时间 76 4.19 utime函数 78 4.20 mkdir和rmdir函数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值