Linux编程之recvmsg和sendmsg函数
recvmsg 和 sendmsg 函数
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
这两个函数把大部分参数封装到一个 msghdr 结构体中:
struct msghdr {
void *msg_name; // protocol address
socklen_t msg_namelen; // size of protocol address
struct iovec *msg_iov; // scatter/gather array
int msg_iovlen; // elements in msg_iov
void *msg_control; // ancillary data (cmsghdr struct)
socklen_t msg_controllen; // length of ancillary data
int msg_flags; // flags returned by recvmsg()
};
- msg_name 和 msg_namelen 这两个成员用于套接字未连接的场合(如未连接 UDP 套接字)。它们类似 recvfrom 和 sendto 的第五个和第六个参数:
- msg_name 指向一个套接字地址结构,调用者在其中存放接收者(对于 sendmsg 调用)或发送者(对于recvmsg调用)的协议地址。如果无需指明协议地址(如对于 TCP 套接字或已连接 UDP 套接字),msg_name 应置为空指针。
- msg_namelen 对于 sendmsg 是一个值参数,对于 recvmsg 却是一个值-结果参数。
- msg_iov 和 msg_iovlen 这两个成员指定输入或输出缓冲区数组(即iovec结构数组),类似 readv 或 writev 的第二个和第三个参数。
- msg_control 和 msg_controllen 这两个成员指定可选的辅助数据的位置和大小。msg_controllen 对于 recvmsg 是一个值-结果参数。
对于 recvmsg 和 sendmsg,必须区别它们的两个标志变量:
- 一个是传递值的 flags 参数;
- 另一个是所传递 msghdr 结构的 msg_flags 成员,它传递的是引用,因为传递给函数的是该结构的地址。
- 只有 recvmsg 使用 msg_flags 成员。recvmsg 被调用时,flags 参数被复制到 msg_flags 成员,并由内核使用其值驱动接收处理过程。内核还依据 recvmsg 的结果更新 msg_flags 成员的值。
- sendmsg 则忽略 msg_flags 成员,因为它直接使用 flags 参数驱动发送处理过程。这一点意味着如果想在某个 sendmsg 调用中设置 MSG_DONTWAIT 标志,那就把 flags 参数设置为该值,把 msg_flags 成员设置为该值不起作用。
recvmsg 返回的 7 个标志如下:
- MSG_BCAST:本标志随 BSD/OS 引入,相对较新。它的返回条件是本数据包作为链路层广播收取或者其目的 IP 地址是一个广播地址。与 IP_RECVD-STADDR 套接字选项相比,本标志是用于判定一个 UPD 数据包是否发往某个广播地址的更好方法。
- MSG_MCAST:本标志随 BSD/OS 引入,相对较新。它的返回条件是本数据报作为链路层多播收取。
- MSG_TRUNC:本标志的返回条件是本数据报被截断,也就是说,内核预备返回的数据超过进程事先分配的空间(所有 iov_len 成员之和)。
- MSG_CTRUNC:本标志的返回条件是本数据报的辅助数据被截断,也就是说,内核预备返回的辅助数据超过进程事先分配的空间(msg_controllen)。
- MSG_EOR:本标志的返回条件是返回数据结束一个逻辑记录。TCP 不使用本标志,因为它是一个字节流协议。
- MSG_OOB:本标志绝不为 TCP 带外数据返回。它用于其他协议族(如 OSI 协议族)。
- MSG_NOTIFICATION:本标志由 SCTP 接收者返回,指示读入的消息是一个事先通知,而不是数据消息。
下图展示了一个 msghdr 结构以及它指向的各种信息。图中假设进程即将对一个 UDP 套接字调用 recvmsg:

图中给协议地址分配了 16 个字节,给辅助数据分配了 20 个字节。为缓冲数据初始化了一个由 3 个 iovec 结构构成的数组:第一个指定一个 100 字节的缓冲区,第二个指定一个 60 字节的缓冲区,第三个指定一个 80 字节的缓冲区。假设已为这个套接字设置了 IP_RECVDSTADDR 套接字选项,以接收所读取 UDP 数据包的目的 IP 地址。
假设从 198.38.100:2000 到达一个 170 字节的 UDP 数据报,它的目的地是我们的 UDP 套接字,目的 IP 地址为 206.168.112.96.下图展示了 recvmsg 返回时 msghdr 结构中的所有信息。

图中被 recvmsg 修改过的字段标上了阴影。从第一幅图到第二幅图的变动包括以下几点:
- 由 msg_name 成员指向的缓冲区被填以一个网际网套接字地址结构,其中有所收到数据报的源 IP 地址和源 UPD 端口号。
- msg_namelen 成员(一个值-结果参数)被更新为存放在 msg_name 所指缓冲区中的数据量。本成员并无变化,因为 recvmsg 调用前和返回后其值均为 16.
- 所收取数据报的前 100 个字节数据存放在第一个缓冲区,中 60 字节数据存放在第二个缓冲区,后 10 字节数据存放在第三个缓冲区。最后那个缓冲区的后 70 字节没有改动。recvmsg 函数的返回值(即 170)就是该数据报的大小。
- 由 msg_control 成员指向的缓冲区被填以一个 cmsghdr 结构。该 cmsghdr 结构中,cmsg_len 成员值为 16,cmsg_level 成员值为 IPPROTO_IP,cmsg_type 成员值为 IP_RECVDSTADDR,随后 4 个字节存放所收到 UDP 数据报的目的 IP 地址。这个 20 字节缓冲区的后 4 个字节没有改动。
- msg_controllen 成员被更新为所存放辅助数据的实际数据量。本成员也是一个值-结果参数,recvmsg 返回时其结果为 16。
- msg_flags 成员同样被 recvmsg 更新,不过没有标志返回给进程。
Linux编程之recvmsg和sendmsg函数的更多相关文章
- socket编程:recvmsg 和 sendmsg 函数
背景 复习 socket 编程的时候发现了以前没有留意到的 2个函数:recvmsg 和 sendmsg ref : Linux编程之recvmsg和sendmsg函数 知识 先来看看函数原型: #i ...
- linux网络编程之shutdown() 与 close()函数详解
linux网络编程之shutdown() 与 close()函数详解 参考TCPIP网络编程和UNP: shutdown函数不能关闭套接字,只能关闭输入和输出流,然后发送EOF,假设套接字为A,那么这 ...
- 03 shell编程之case语句与函数
本文所有内容均来自当年博主当年学习笔记,若有不足欢迎指正 Shell编程之case语句与函数 学习目标: 掌握case语句编程 掌握shell函数的使用 目录结构: Case语句 Case语句的作用 ...
- Linux编程之ICMP洪水攻击
我的上一篇文章<Linux编程之PING的实现>里使用ICMP协议实现了PING的程序,ICMP除了实现这么一个PING程序,还有哪些不为人知或者好玩的用途?这里我将介绍ICMP另一个很有 ...
- PHP Socket 编程之9个主要函数的使用之测试案例
php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络 ...
- Linux多任务编程之二:fork()函数及其基础实验(转)
来源:CSDN 作者:王文松 转自Linux公社 fork()函数 在 Linux 中创建一个新进程的唯一方法是使用fork()函数.fork()函数是 Linux 系统中一个非常重要的函数,和咱们 ...
- recvmsg和sendmsg函数
这两个函数是最通用的I/O函数.实际上我们把所有read.readv.recv和recvfrom调用替换成recvmsg调用.类似地,各种输出函数调用也可以替换成sendmsg调用 #include ...
- UNIX网络编程读书笔记:recvmsg和sendmsg函数
这两个函数是最通用的I/O函数.实际上我们可以把所有read.readv.recv和recvfrom调用替换成recvmsg调用.类似地,各种输出函数调用也可以替换成sendmsg调用. #inclu ...
- Linux编程之fork函数
在Linux中,fork函数的功能就是在一个进程中创建一个新的进程,当前调用fork函数的进程就是产生的新进程的父进程,新进程在以下也称为子进程.在新进程生成之后就会在系统中开始执行. 函数原型:pi ...
随机推荐
- UML中的类图
模型 类 接口 关系 关联关系 描述了类的结构之间的关系.具有方向.名字.角色和多重性等信息.一般的关联关系语义较弱.也有两种语义较强,分别是聚合与组合 聚合 特殊关联关系,指明一个聚集(整体)和组成 ...
- ELECTRON 打包
安装electron-packager cnpm install electron-packager -g 配置package.json "scripts": { "st ...
- You are using the runtime-only build of Vue where the template compiler is not available.
使用vue-cli搭建的项目,启动报错 You are using the runtime-only build of Vue where the template compiler is not a ...
- 使用 django-redis 作缓存
1 缓存内容使用 django支持多种不同的cache backend,默认使用的是localmem,django-redis 是一个使django支持 redis cache的功能组件. 安装 p ...
- 将windows当做linux/Mac来用 scoop强大的包管理工具
在Linux中有apt-get.yum这些包安装管理 安装相当方便:如ubuntu安装一个mysql5.7,只需要一个简单的命令: apt-get 而在windows中需要在MySQL官网下载对应版本 ...
- linux下安装db2
最近研究了一下在 ubuntu下安装db2的过程,很快就完成安装,特贴出来供大家讨论,如有错误请多多指教. 注意:安装过程请使用root用户,否则会出现安装失败的情况: 安装过程: 准备工作: 准备安 ...
- Django—logging配置
我写Django项目常用的logging配置. # Django的日志配置项 BASE_LOG_DIR = os.path.join(BASE_DIR, "log") LOGGIN ...
- 09_Redis_消息订阅与发布
一:Redis 发布订阅 Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息. Redis 客户端可以订阅任意数量的频道. 下图展示了频道 c ...
- org.apache.tomcat.util.descriptor.web.WebXml.setVersion Unknown version string [4.0]
错误: 在 IDEA 创建WEB项目之后,打印出的日志中总是出现一行警告信息: 12-May-2018 15:52:30.692 警告 [RMI TCP Connection(3)-127.0.0.1 ...
- bzoj 1787 && bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)算法竞赛进阶指南
题目描述 原题连接 Y岛风景美丽宜人,气候温和,物产丰富. Y岛上有N个城市(编号\(1,2,-,N\)),有\(N-1\)条城市间的道路连接着它们. 每一条道路都连接某两个城市. 幸运的是,小可可通 ...