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

来源:互联网 发布:谜一样的双眼知乎 编辑:程序博客网 时间:2024/06/16 04:20

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


STREAMS 消息

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

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

[cpp] view plaincopy
  1. struct strbuf  
  2. {  
  3.        int maxlen;  /* size of buffer */  
  4.        int len;         /* number of bytes currently in buffer */  
  5.        char *buf;    /* pointer to buffer */  
  6. };  
 
        当使用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 消息写至流中,这两个函数的区别是后者允许对消息指定一个优先级波段。

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

STREAMS 的 ioctl 操作

        ioctl 函数如下:

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

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * 函数功能:判断描述符是否引入一个流; 
  3.  * 返回值:若为STREAMS设备则返回1,否则返回0; 
  4.  * 函数原型: 
  5.  */  
  6. #include <stropts.h>  
  7. int isastream(int filedes);  
  8. /* 
  9.  * 说明: 
  10.  * 该函数是通过ioctl函数来进行的,可有如下实现: 
  11.  */  
  12. #include <stropts.h>  
  13. #include <unistd.h>  
  14. int isastream(int fd)  
  15. {  
  16.     return(ioctl(fd, I_CANPUT, 0) != -1);  
  17. }  

写模式

        可以使用两个 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 函数


[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* 
  2.  * 函数功能:将从流读STREAMS消息; 
  3.  * 返回值:若成功则返回非负值,若出错则返回-1; 
  4.  * 函数原型: 
  5.  */  
  6. #include <stropts.h>  
  7. int getmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int *flagptr);  
  8. int getpmsg(int filedes, const struct strbuf *ctlptr, const struct strbuf *datptr, int *bandptr, int *flagptr);  
  9. /* 
  10.  * 说明: 
  11.  * 如果flagptr指向的整型单元的值是0,则getmsg返回流首读队列中的下一个消息; 
  12.  * 如果下一个消息是最高优先级消息,则在返回时,flagptr所指向的整型单元设置为RS_HIPRI; 
  13.  * 如果只希望接收高优先级消息,则在调用getmsg之前必须将flagptr所指向的整型单元设置为RS_HIPRI; 
  14.  * getmsg可以设置待接收消息的优先级波段; 
  15.  */  
0 0
原创粉丝点击