2010-11-23 175 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邊界不會被保留)。