如您所知 sendmsg 具有以下声明:int sendmsg(int s, const struct msghdr *msg, int flags);
而 msghdr 结构具有以下形式:
struct msghdr {
void * msg_name; /* optional address */
socklen_t msg_namelen; /* size of address */
struct iovec * msg_iov; /* scatter/gather array */
size_t msg_iovlen; /* # elements in msg_iov */
void * msg_control; /* ancillary data, see below */
socklen_t msg_controllen; /* ancillary data buffer len */
int msg_flags; /* flags on received message */
};
如您所见,msghdr具有一个数组iovec缓冲区,并且缓冲区计数为msg_iovlen。我想知道的是sendmsg如何发送这些缓冲区。它是连接所有缓冲区并发送还是在for循环中发送?
最佳答案
手册页提到了一条消息(单数)和多个元素(复数):
对于流套接字,无论哪种方式都没有关系。您发送的任何数据都将最终成为另一端的一长串数据流。
对于数据报或消息套接字,我可以理解为什么再进行一些澄清会有所帮助。但是似乎您只通过一个sndmsg
调用就发送了一个数据报或消息。每个缓冲区元素一个。
出于好奇,我实际上是在研究Linux源代码,以便对这个答案有更好的了解。看起来send
和sendto
只是Linux中sendmsg
的包装器,它们为您构建了struct msghdr
。实际上,UDP sendmsg
实现为每个sendmsg
调用留出一个UDP header 的空间。
如果您担心性能,那么仅传递一个sendmsg
似乎就不会从iovec
中受益。但是,如果您要在用户空间中串联缓冲区,则可能会为您赢得一些机会。
它有点类似于writev
,其附加好处是您可以指定用于无连接套接字(如UDP)的目标地址。如果您喜欢这种事情,还可以添加辅助数据。 (通常用于在UNIX域套接字之间发送文件描述符。)