這兩個函數是最通用的I/O函數。實際上我們可以把所有read、readv、recv和recvfrom調用替換成recvmsg調用。類似地,各種輸出函數調用也可以替換成sendmsg調用。
#include <sys/socket.h> sockfd, msghdr *msg, sockfd, msghdr *msg, -——出錯
這兩個函數把大部分參數封裝到一個msghdr結構中:
*msg_name; iovec *msg_iov; msg_iovlen; *msg_control; msg_flags;
這裡給出的msghdr結構符合POSIX規範。有些系統仍然使用本結構源自4.2BSD的較舊版本。這個較舊的結構沒有msg_flags成員,而且msg_control和msg_controllen成員分別被稱為msg_accrights和msg_accrightslen。這個較舊結構唯一支援的輔助資料形式用於傳遞檔案描述字(稱為存取權限)。
msg_name和msg_namelen這兩個成員用於套介面未串連的場合(譬如未串連UDP套介面)。它們類似reacvfrom和sendto的第5和第6個參數:msg_name指向一個套介面地址結構,調用者在其中存放接收者(對於sendmsg調用)或寄件者(對於recvmsg調用)的協議地址。如果無需指明協議地址(例如對於TCP套介面或已串連UDP套介面),msg_name應置為空白指標。msg_namelen對於sendmsg是一個值參數,對於recvmsg卻是一個值-結果參數。
msg_iov和msg_iovlen這兩個成員指定輸入或輸出緩衝區數組(即iovec結構數組),類似readv和writev的第2和第3個參數。
msg_control和msg_controllen這兩個成員指定可選的輔助資料的位置和大小。
對於recvmsg和sendmsg,我們必須區別它們的兩個標誌變數:一個是傳遞值的flags參數,另一個是所傳遞msghdr結構的msg_flags成員,它傳遞的是引用,因為傳遞給函數的是該結構的地址。
標誌 核心檢查:
send flags
sendto flags
sendmsg flags 核心檢查:
recv flags
recvfrom flags
recvmsg flags 核心返回:
recvmsg msg_flags MSG_DONTROUTE
MSG_DONTWAIT
MSG_PEEK
MSG_WAITALL MSG_EOR
MSG_OOB MSG_MCAST
MSG_TRUNC
MSG_CTRUNC
MSG_NOTIFICATION
這些標誌中,核心只檢查而不返回前4個標誌;既檢查又返回下2個標誌;不檢查而只返回後5個標誌。recvmsg返回的7個標誌解釋如下:
MSG_BCAST 本標誌隨BSD/OS引入,相對較新。它的返回條件是:本資料報作為鏈路層廣播收取或者其宿IP地址是一個廣播位址。
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地址。
我們接著假設從192.6.38.100連接埠2000到達一個170位元組的UDP資料報,它的目的地是我們的UDP套介面,宿IP地址為206.168.112.96。如所示,展示了recvmsg返回時msghdr結構中的所有資訊。(圖中被修改過的欄位標了陰影)
如所示為5組I/O函數之間的差異: