文档章节

网络编程学习——高级I/O函数

thanatos_y
 thanatos_y
发布于 2016/04/20 09:40
字数 2024
阅读 20
收藏 0

1 概述

  在I/O操作上设置超时,这里有三种方法。然后read和write这两个函数的三个变体:recv和send允许通过第四个参数从进程到内核传递标志;readv和writev允许指定往其中输入数据或从其中输出数据的缓冲区向量;recvmsg和sendmsg结合了其他I/O函数的所有特性,并具有接收和发送辅助数据的新能力。

2 套接字超时

  在套解字I/O上设置超时的方法有以下三种;

  1. 调用alarm,它在指定超时期满时产生SIGALRM信号。这个方法涉及信号处理,而信号处理在不同的实现上存在差异,而且可能干扰进程中现有alarm调用。

  2. 在select中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在read或write调用上。

  3. 使用较新的SO_REVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并非所有实现都支持这两个套接字选项。

3 recv和send函数

  这两个函数类似标准read和write函数,不过需要一个额外的参数。

#include <socket.h>
/* Read N bytes into BUF from socket FD.
   Returns the number read or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t recv (int __fd, void *__buf, size_t __n, int __flags);

/* Send N bytes of BUF to socket FD.  Returns the number sent or -1.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t send (int __fd, const void *__buf, size_t __n, int __flags);

  I/O函数的flag值。

图1-1 I/O函数的flags参数

 

4 readv和writev函数

  readv和writev允许单个系统调用读入到或写出自一个或多个缓冲区。这些操作分别称为分散读(scatter read)和集中写(gather write),因为来自读操作的输入数据被分散到多个应用缓冲区,而来自多个应用缓冲区的输出数据则被集中提供给单个写操作。

#include <bits/uio.h>

/* Structure for scatter/gather I/O.  */
struct iovec
  {
    void *iov_base;    /* Pointer to data.  */
    size_t iov_len;    /* Length of data.  */
  };


#include <sys/uio.h>

/* Read data from file descriptor FD, and put the result in the
   buffers described by IOVEC, which is a vector of COUNT 'struct iovec's.
   The buffers are filled in the order specified.
   Operates just like 'read' (see <unistd.h>) except that data are
   put in IOVEC instead of a contiguous buffer.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t readv (int __fd, const struct iovec *__iovec, int __count)
  __wur;

  
/* Write data pointed by the buffers described by IOVEC, which
   is a vector of COUNT 'struct iovec's, to file descriptor FD.
   The data is written in the order specified.
   Operates just like 'write' (see <unistd.h>) except that the data
   are taken from IOVEC instead of a contiguous buffer.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t writev (int __fd, const struct iovec *__iovec, int __count)
  __wur;

  writev是一个原子操作。

5 recvmsg和sendmsg函数

  这两个函数是最通用的I/O函数。实际上我们可以把所有read、readv、recv和recvfrom调用替换成recvmsg调用。类似地,各种输出函数调用也可以替换成sendmsg调用。

#include <socket.h>

/* Send a message described MESSAGE on socket FD.
   Returns the number of bytes sent, or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern ssize_t sendmsg (int __fd, const struct msghdr *__message,
            int __flags);
            
/* Send a VLEN messages as described by VMESSAGES to socket FD.
   Returns the number of datagrams successfully written or -1 for errors.

   This function is a cancellation point and therefore not marked with
   __THROW.  */
extern int sendmmsg (int __fd, struct mmsghdr *__vmessages,
             unsigned int __vlen, int __flags);

  这两个函数把大部分参数封装到一个mmshdr。

#include <socket.h>
/* For `recvmmsg' and `sendmmsg'.  */
struct mmsghdr
  {
    struct msghdr msg_hdr;    /* Actual message header.  */
    unsigned int msg_len;    /* Number of received or sent bytes for the
                   entry.  */
  };
    
#include <sys/socket.h>

  /* Structure describing messages sent by
   `sendmsg' and received by `recvmsg'.  */
struct msghdr
  {
    void *msg_name;        /* Address to send to/receive from.  */
    socklen_t msg_namelen;    /* Length of address data.  */

    struct iovec *msg_iov;    /* Vector of data to send/receive into.  */
    size_t msg_iovlen;        /* Number of elements in the vector.  */

    void *msg_control;        /* Ancillary(辅助数据) data (eg BSD filedesc passing). */
    size_t msg_controllen;    /* Ancillary data buffer length.
                   !! The type should be socklen_t but the
                   definition of the kernel is incompatible
                   with this.  */

    int msg_flags;        /* Flags on received message.  */
  };

  图1-2汇总了内核为输入和输出函数检查的flags参数值以及recvmsg可能返回的msg_flag成员值。其中没有sendmsg msg_flags一栏,因为我们已提及本组合无效。

图1-2 各种I/O函数输入和输出标志的总结

  图1-3展示了一个msghdr结构以及它指向的各种信息。

图1-3 对一个UDP套接字调用recvmsg时的数据结构

  图1-4展示了recvmsg返回时msghdr结构中的所有信息。

  图1-5汇总了我们已讲述的5组I/O函数之间的差异。

图1-5 5组I/O函数的比较

 

6 辅助数组

  辅助数据(ancillary data)可通过调用sendmsg和recvmsg这两个函数,使用msghdr结构中的msg_control和msg_controllen这两个成员发送和接收。辅助数据的另一个称谓是控制信息(control information)。图1-6汇总了辅助数据的各种用途。

图1-6 辅助数据用途的总结

  辅助数据由一个或多个辅助数据对象(ancillary data object)构成,每个对象以一个定义在头文件<bits/socket.h>中的cmsghdr结构开头。

/* Structure used for storage of ancillary data object information.  */
struct cmsghdr
  {
    size_t cmsg_len;        /* Length of data in cmsg_data plus length
                   of cmsghdr structure.
                   !! The type should be socklen_t but the
                   definition of the kernel is incompatible
                   with this.  */
    int cmsg_level;        /* Originating protocol.  */
    int cmsg_type;        /* Protocol specific type.  */
#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
    __extension__ unsigned char __cmsg_data __flexarr; /* Ancillary data.  */
#endif
  };

  图1-7展示了在一个控制缓冲区出现2个辅助数据对象的例子。

图1-7 包含两个辅助数据对象的辅助函数

  图1-8显示了通过一个Unix域套接字传递描述符或传递凭证时所用cmshhdr结构的格式。

图1-8 用在Unix域套接字上的cmsghdr结构

  既然由recvmsg返回的辅助数据可含有任意数目的辅助数据对象,为了对应用程序屏蔽可能出现的填充字节,头文件<bits/socket.h>中定义了以下5个宏,以简化对辅助数据的处理。

#if (!defined __STRICT_ANSI__ && __GNUC__ >= 2) || __STDC_VERSION__ >= 199901L
# define CMSG_DATA(cmsg) ((cmsg)->__cmsg_data)
#else
# define CMSG_DATA(cmsg) ((unsigned char *) ((struct cmsghdr *) (cmsg) + 1))
#endif
#define CMSG_NXTHDR(mhdr, cmsg) __cmsg_nxthdr (mhdr, cmsg)
#define CMSG_FIRSTHDR(mhdr) \
  ((size_t) (mhdr)->msg_controllen >= sizeof (struct cmsghdr)              \
   ? (struct cmsghdr *) (mhdr)->msg_control : (struct cmsghdr *) 0)
#define CMSG_ALIGN(len) (((len) + sizeof (size_t) - 1) \
             & (size_t) ~(sizeof (size_t) - 1))
#define CMSG_SPACE(len) (CMSG_ALIGN (len) \
             + CMSG_ALIGN (sizeof (struct cmsghdr)))
#define CMSG_LEN(len)   (CMSG_ALIGN (sizeof (struct cmsghdr)) + (len))

  这些宏能以如下伪代码形式使用。

  CMSG_SPACE要记可能出现的尾部的填充字节,而CMSG_LEN不会。

7 排队的数据量

  有时候我们想知道在不真正读取数据的前提下直到一个套接字上已有多少数据排队等着读取。有3个技术可用于获悉已排队的数据量。

  1. 如果获悉已排队数据量的目的在于避免读操作阻塞在内核中,那么可以使用非阻塞式I/O。

  2. 如果我们既想查看数据,又想数据仍然留在接收队列中以供本进程其他部分稍后读取,那么可以使用MSG_PEEK标志。

  3. 一些实现支持ioctl的FINONREAD命令。

8 kqueue接口

  本接口允许进程向内核注册描述所关注kqueue事件的事件过滤器(event filter)。事件除了与select所关注类似的文件I/O和超时外,还有异步I/O、文件修改通知(例如文件被删除或修改时发生的通知)、进程跟踪(例如进程调用exit或fork时发出通知)和信号处理。kqueue接口包括如下2个函数和1个宏。

  kqueue函数返回一个新的kqueue描述符,用于后序调用的kevent调用中。kevent函数既用于注册所关注的事件,也用于确定是否有所关注事件发生。

   其中flags成员在调用时指定过滤器更改行为,在返回时额外给出条件,如图1-9所示。

图1-9 kevent结构的flags成员

  filter成员指定的过滤器类型如图1-10所示。

图1-10 kevent结构的filter成员

 


 

 

 

 

 

 

 

 

© 著作权归作者所有

共有 人打赏支持
thanatos_y
粉丝 7
博文 112
码字总数 315059
作品 0
成都
程序员
私信 提问
0-Linux 网络编程修炼指南——内功心法

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q1007729991/article/details/69091877 学习交流群: Linux 学习交流群 610441700 说明:本系列文章并不能取代...

--Allen--
2017/04/04
0
0
【求职】:嵌入式软件工程师,各位前辈,给点意见,看看我能拿多少工资!!多谢

简历 基本信息: 姓 名: 陈 健 性 别: 男 相 片 出生日期: 1989-12-26 民 族: 汉 学 历: 本 科 毕业学院: 山东工商学院 健康状况: 良好 联系电话: ********* 语言状况: 英语四级 联...

一两茶叶
2011/10/19
3.2K
8
Qzone 微信 Java高级——dubbo源码分析之远程通信 netty

Java高级——dubbo源码分析之远程通信 netty dubbo 底层通信选择了 netty 这个 nio 框架做为默认的网络通信框架并且通过自定义协议进行通信。dubbo 支持以下网络通信框架: Netty(默认) Min...

Java架构师那些事
08/29
0
0
《Node.js开发指南》书评汇总

刚查了下库存,发现订阅《Node.js开发指南》的读者大增,这是为什么呢?看了下近期本书在豆瓣的评论,口碑很好,现将豆瓣的书评汇总如下: ----------------------------------------------...

生气的散人
2012/10/15
3.2K
3
程序人生——为什么高级、初级程序员都重要呢?

每个找工作的程序员都必然会遇到这样的招聘贴:寻找“高级程序员”或“初级/入门级程序员”——也许你并没有真正理解这两者之间的区别。与此同时,许多招聘经理可能也不明白其中的区别,他们...

欧阳海阳
07/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

集群介绍 ..

12月19日任务 18.1 集群介绍 18.2 keepalived介绍 18.3/18.4/18.5 用keepalived配置高可用集群 一.集群介绍 根据功能划分为两大类:高可用和负载均衡 高可用集群通常为两台服务器,一台工作,...

hhpuppy
20分钟前
0
0
TensorFlow的基础概念02

TensorFlow的计算流图 import osos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'#TensorFlow的计算模型,数据流图'''TensorFlow = Tensor + FlowTensor 张量 数据结构:多维数组Flo...

怪咖先生forever
26分钟前
2
0
大数据技术的发展趋势

大数据领域已经涌现出了大量新的技术,它们成为大数据采集、存储、处理和呈现的有力武器。这些技术下一步将如何发展?它们之中哪些技术将广为流行?又会诞生哪些新的技术? 技术趋向多样化,...

董黎明
41分钟前
8
0
藏在正则表达式里的陷阱

前几天线上一个项目监控信息突然报告异常,上到机器上后查看相关资源的使用情况,发现 CPU 利用率将近 100%。通过 Java 自带的线程 Dump 工具,我们导出了出问题的堆栈信息。 我们可以看到所...

前端小攻略
43分钟前
3
0
关联更新,关联查询

关联更新 update A,B SET A.c1=B.c1,A.c2=B.c2 where A.id=B.id and ... update A inner join on A.id=B.id set A.c1=B.c1,A.c2=B.c2 where... 关联查询 交叉连接(cross join),内连接(inner ......

关元
47分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部