2010-11-23 100 views
9

正如你所知道SENDMSG有这样的声明: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循环吗?

+4

只是一个说明:如果这是好奇心,然后很酷。如果你正在尝试写出一些依赖于这些知识的东西,那么你几乎肯定会做错了,并且会出现问题。 – 2010-11-23 17:37:07

+2

@SanJacinto对你来说阐述**为什么**写出一些依赖于这些知识的东西需要麻烦。你能详细说明吗? – 2012-07-09 01:55:09

+1

@lori因为文档为您提供了一组代码界面,并告诉您对它们有什么期望。界面变化非常缓慢。底层代码没有这样的保证。如果你在搜集关于内部的知识,并围绕这些知识编写代码,那么如果你更新内核或网络堆栈中的某个驱动程序,并且调用它的代码不再工作,则不应该感到惊讶。如果你这样做,你做出了不好的选择。 – 2012-07-09 11:07:20

回答

22

的手册页讲的消息(单数)和多个元件(多个):

对于send()sendto(),消息被在buf发现,并具有长度 len。对于sendmsg(),消息由 数组msg.msg_iov的元素指向。调用sendmsg()还允许发送辅助数据 (也称为控制信息)。

对于流套接字,它不会有问题两种方式。您发送的任何数据将最终成为另一端的一个长数据流。

对于数据报或信息插座,我可以看到,为什么更多的清晰度将是有益的。但是看起来你只需要发送一个数据报或者一个sndmsg呼叫;不是每个缓冲区元素一个。

其实我去在Linux源代码挖掘出的好奇心和获取有关这个答案更好的感觉。它看起来像send,并sendto只是在Linux中sendmsg包装,即打造struct msghdr你。而事实上,在UDP sendmsg实施,使得房间每sendmsg呼叫一个 UDP报头。

如果表现是你所担心的,那么看起来你不会从sendmsg中受益,如果你只通过一个iovec。不过,如果你在用户空间连接缓冲区,这可能会让你赢得一些。

这有点类似于writev,与您可以用于连接套接字(如UDP)使用指定目标地址的好处。如果你遇到这种情况,你也可以添加辅助数据。(常用于跨越UNIX域套接字发送文件描述符。)

1

根据http://opengroup.org/onlinepubs/007908799/xns/sendmsg.html ...

从由msg_iov指示的每个存储区域 的数据依次被发送。

我的解释是, sendmsg()不会连接存储在iovec中的消息数据;每个将作为单独的消息发送。

[编辑:我的解释是不正确的;见其他的答案为更好的解释]

1

这取决于您的TCP/IP堆栈。嵌入式TCP/IP堆栈可能会将不同的iovecs直接发送到NIC。但是在通常的TCP/IP协议栈中,必须已经有用户空间内存拷贝到内核空间内存,所以这里没有任何收益,并且iovecs从概念上被复制到单个大块内存中(它可以是单独的内存页面,如果驱动程序支持scather/gather I/O,但这里的重要部分是iovec边界不会被保留)。