文档章节

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

thanatos_y
 thanatos_y
发布于 2016/04/20 09:40
字数 2024
阅读 15
收藏 0
点赞 1
评论 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
博文 90
码字总数 315059
作品 0
成都
程序员
0-Linux 网络编程学习笔记导航

学习交流群: Linux 学习交流群 610441700 说明:本系列文章并不能取代 《UNP》这本旷世之作,文章中难免有错误与不足之处,希望读者们遇到有疑问的地方可以加群互相交流,共同进步。写这一系...

q1007729991 ⋅ 2017/04/04 ⋅ 0

程序员练级-关键提炼

启蒙入门 1.学习一门脚本语言,例如Python/Ruby 2.熟悉Unix/Linux Shell和常见的命令行 3. 学习Web基础(HTML/CSS/JS) + 服务器端技术 (LINUX + APACHE + MYSQL + PHP)      未来必然是W...

zhayefei ⋅ 2013/01/23 ⋅ 4

如何学好C和C++

有人在酷壳的留言版上询问下面的问题 keepwalker : 今天晚上我看到这篇文章。 http://programmers.stackexchange.com/questions/62502/small-c-projects 我也遇到了和提问的老外一样的问题。...

zhangyujsj ⋅ 2015/09/06 ⋅ 0

最优秀的9本开源 C 语言书籍

最优秀的9本开源 C 语言书籍 程序师2017-02-1484 阅读 C语言业界观察 书是非常私人的东西,编程类书籍也不例外。我们都是通过阅读书籍来帮助掌握某种语言的基本知识。随后又通过阅读书籍来全...

程序师 ⋅ 2017/02/14 ⋅ 0

通过这 9 本开源好书学习 C 语言

本文由伯乐在线 -艾凌风 翻译。未经许可,禁止转载! 英文出处: Steve Emms。欢迎加入翻译组。 书是非常私人的东西,编程类书籍也不例外。我们都是通过阅读书籍来帮助掌握某种语言的基本知识...

伯乐在线 ⋅ 2017/02/14 ⋅ 0

《Node.js开发指南》书评汇总

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

生气的散人 ⋅ 2012/10/15 ⋅ 0

C语言已死(连载1)——趣味、通俗、实用的计算机达人成长之路之C语言高级技巧篇

第一章 学习C语言的起跑线 本书描述的就是使用C语言的高级技巧,力求将你的C语言能力由“基础”提升为“高级”。但是学习态度胜过学习方法,在正式学习之前,有一个问题不吐不快,那就是“C...

zhuyunxiang ⋅ 2011/08/15 ⋅ 0

一个月入门Python爬虫,快速获取大规模数据

数据是创造和决策的原材料,高质量的数据都价值不菲。而利用爬虫,我们可以获取大量的价值数据,经分析可以发挥巨大的价值,比如: 豆瓣、知乎:爬取优质答案,筛选出各话题下热门内容,探索...

Python开发者 ⋅ 04/25 ⋅ 0

(转) 坚持完成这套学习手册,你就可以去 Google 面试了

C++ —— 不使用内建的数据类型。C++ —— 使用内建的数据类型,如使用 STL 的 std::list 来作为链表。Python —— 使用内建的数据类型(为了持续练习 Python),并编写一些测试去保证自己代...

wangxiaocvpr ⋅ 2016/10/12 ⋅ 0

我的网络开发之旅——socket编程

上一篇文章《TCP/IP协议分析》讲述了自己是如何和网络领域的开发扯上关系的。正如从招聘网站上抽出的几个关键词“TCP/IP, Socket, 多线程”可见,协议分析并不是网络开发的主流,通常我们所说...

yaocoder ⋅ 2014/09/21 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

android -------- 颜色的半透明效果配置

最近有朋友问我 Android 背景颜色的半透明效果配置,我网上看资料,总结了一下, 开发中也是常常遇到的,所以来写篇博客 常用的颜色值格式有: RGB ARGB RRGGBB AARRGGBB 这4种 透明度 透明度...

切切歆语 ⋅ 12分钟前 ⋅ 0

CentOS开机启动subversion

建立自启动脚本: vim /etc/init.d/subversion 输入如下内容: #!/bin/bash## subversion startup script for the server## chkconfig: 2345 90 10# description: start the subve......

随风而飘 ⋅ 15分钟前 ⋅ 0

Nginx + uwsgi @ubuntu

uwsgi 安装 sudo apt-get install python3-pip # 注意 ubuntu python3默认没有安装pippython3 -m pip install uwsgi 代码(test.py) def application(env, start_response): start_res......

袁祾 ⋅ 16分钟前 ⋅ 0

版本控制工具

CSV , SVN , GIT ,VSS

颖伙虫 ⋅ 18分钟前 ⋅ 0

【2018.06.19学习笔记】【linux高级知识 13.1-13.3】

13.1 设置更改root密码 13.2 连接mysql 13.3 mysql常用命令

lgsxp ⋅ 26分钟前 ⋅ 0

LVM

LVM: 硬盘划分分区成物理卷->物理卷组成卷组->卷组划分逻辑分区。 1.磁盘分区: fdisk /dev/sdb 划分几个主分区 输入t更改每个分区类型为8e(LVM) 使用partprobe生成分区的文件:如/dev/sd...

ZHENG-JY ⋅ 54分钟前 ⋅ 0

彻底删除Microsoft Office的方法

参照此链接彻底删除Office https://support.office.com/zh-cn/article/%e4%bb%8e-pc-%e5%8d%b8%e8%bd%bd-office-9dd49b83-264a-477a-8fcc-2fdf5dbf61d8?ui=zh-CN&rs=zh-CN&ad=CN......

Kampfer ⋅ 今天 ⋅ 0

大盘与个股之间关系

大盘走多:积极出手 顺势加码 大盘走空: 少量出手 退场观望 大盘做头:逆势减码 少量操作 大盘做底 : 小量建仓 小量试单

guozenhua ⋅ 今天 ⋅ 0

Day16 LVM(逻辑卷管理)与磁盘故障小案例

lvm详解 简述 LVM的产生是因为传统的分区一旦分区好后就无法在线扩充空间,也存在一些工具能实现在线扩充空间但是还是会面临数据损坏的风险;传统的分区当分区空间不足时,一般的解决办法是再...

杉下 ⋅ 今天 ⋅ 0

rsync实现多台linux服务器的文件同步

一、首先安装rsync,怎样安装都行,rpm,yum,还是你用源码安装都可以。因为我用的是阿里云的ESC,yum install rsync就ok了。 二、配置rsync服务 1.先建立个同步数据的帐号 123 groupadd r...

在下头真的很硬 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部