socket编程:recvmsg 和 sendmsg 函数
背景
复习 socket 编程的时候发现了以前没有留意到的 2个函数:recvmsg 和 sendmsg
知识
先来看看函数原型:
#include <sys/types.h>
#include <sys/socket.h>
...
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);
...
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);
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 是一个值-结果参数。
flags
对于 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 更新,不过没有标志返回给进程。
socket编程:recvmsg 和 sendmsg 函数的更多相关文章
- Linux编程之recvmsg和sendmsg函数
recvmsg 和 sendmsg 函数 #include <sys/types.h> #include <sys/socket.h> ssize_t send(int soc ...
- socket编程中客户端常用函数
1 常用函数 1.1 connect() int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen); 客 ...
- UNIX网络编程读书笔记:recvmsg和sendmsg函数
这两个函数是最通用的I/O函数.实际上我们可以把所有read.readv.recv和recvfrom调用替换成recvmsg调用.类似地,各种输出函数调用也可以替换成sendmsg调用. #inclu ...
- recvmsg和sendmsg函数
这两个函数是最通用的I/O函数.实际上我们把所有read.readv.recv和recvfrom调用替换成recvmsg调用.类似地,各种输出函数调用也可以替换成sendmsg调用 #include ...
- socket编程中服务器端常用函数 以及简单实现
1 常用函数 1.1 socket() int socket(int family, int type, int protocol); socket()打开一个网络通讯端口,如果成功的话,返回一个 ...
- c++ 网络编程(五) LINUX下 socket编程 多种I/O函数 -以及readv和writev函数用法
原文作者:aircraft 原文链接:https://www.cnblogs.com/DOMLX/p/9614056.html 一.多种I/O函数 前言:之前我们讲的数据传输一般Linux上用writ ...
- socket编程中客户端常用函数 以及简单实现
1 常用函数 1.1 connect() int connect(int sockfd, const struct sockaddr *servaddr, socklen_taddrlen); 客 ...
- PHP Socket编程 之使用fsockopen()函数
Socket可以理解为两台计算机相互通信的通道. 用法:使用fsockopen()函数 具体用法详见上篇文章.函数的参数为URL.端口号.一个存放错误编号的变量.一个存放错误信息字符串的变量和超时等待 ...
- Socket编程 之使用fsockopen()函数
fsockopen函数:初始化一个套接字连接到指定主机(hostname) get方式: client.php <?php //创建连接 $fp=fsockopen('localhost',80 ...
随机推荐
- 消息队列之事务消息,RocketMQ 和 Kafka 是如何做的?
每个时代,都不会亏待会学习的人. 大家好,我是 yes. 今天我们来谈一谈消息队列的事务消息,一说起事务相信大家都不陌生,脑海里蹦出来的就是 ACID. 通常我们理解的事务就是为了一些更新操作要么都成 ...
- Centos-分割文件-split
split 分割文件,将一个文件分割为多个 相关选项 -b 指定文件大小,可以在size后面添加单位后缀,b表示512字节,k表示1KB,m表示MB -n 指定分割文件的长度,默认为1000行 -d ...
- 【题解】[CH弱省胡策R2]TATT
本蒟蒻第一道\(K-D-Tree\)维护\(dp\) Question 题目大意:求一条路径,使得其四个维度单调不降. 先排序消掉一维再说. 对于每一个点,初始的时候绝对长度是1啊.于是,先赋值一个1 ...
- 用 Java 实现的八种常用排序算法
八种排序算法可以按照如图分类 交换排序 所谓交换,就是序列中任意两个元素进行比较,根据比较结果来交换各自在序列中的位置,以此达到排序的目的. 1. 冒泡排序 冒泡排序是一种简单的交换排序算法,以升序排 ...
- vue 项目打包后静态资源加载不到
1, 2,
- 题解:CF593D Happy Tree Party
题解:CF593D Happy Tree Party Description Bogdan has a birthday today and mom gave him a tree consistin ...
- MeteoInfoLab脚本示例:数据投影-FLEXPART
FLEXPART是一个类似HYSPLIT的扩散模式,它输出的netcdf文件参照了WRF,可惜全局属性没有写全,比如只有一个投影名称(例如Lambert),没有相关的投影参数:中央经度,标准纬度等等. ...
- 工业级wifi模块
工业级wifi模块 工业级wifi模块ZLSN7004是上海卓岚开发的一款高性能的Wifi.以太网转串口模块.与普通的wifi模块定位在低成本不同,7004定位在高稳定性.丰富功能,设计目标是面向对功 ...
- GA001-181-21
Composite State with History The Composite State with History Pattern describes an entity (e.g. Cl ...
- spring boot:接收数组参数及多文件混合json参数(spring boot 2.3.4)
一,生产环境中的复杂参数上传的场景 1,保存排序值 : 例如:某一件商品的多张展示图片排序,提交的排序值要和图片的id相对应 2,上传多张图片,图片要和指定的变量相对应 例如:在添加商品sku时, 需 ...