在套接字上發送消息
系統調用send()、sendto()和sendmsg()用於將消息傳輸到另壹個套接字。
Send()只能在socket連接的情況下調用(為了知道預期的接收方,也就是說send()只用於數據流類型的數據傳輸,對於TCP,服務器端和客戶端都可以使用send/recv;;但是對於UDP,只有客戶端可以使用send/recv
在套接字上發送消息
系統調用send()、sendto()和sendmsg()用於將消息傳輸到另壹個套接字。
Send()只能在socket連接的情況下調用(為了知道預期的接收方,也就是說send()只用於數據流類型的數據傳輸,對於TCP,服務器端和客戶端都可以使用send/recv;;但是對於UDP,只有客戶端可以使用send/recv,服務器端只能使用sendto/recvfrom,因為客戶端在connect操作之後才知道要發送和接受的地址。send()和write(2)之間的唯壹區別是flags參數的存在。另外,
send(sockfd,buf,len,flags);
等於
sendto(sockfd,buf,len,flags,NULL,0);
參數sockfd是發送方套接字的文件描述符。
如果在連接模式下對套接字使用sendto()(即套接字類型為SOCK_STREAM和SOCK_SEQPACKET),參數dest_addr和addrlen將被忽略(當它們不為NULL和0時,可能返回錯誤EISCONN),如果套接字沒有實際連接(在三次握手中沒有建立連接),將返回錯誤ENOTCONN。否則,目標地址由dest_addr給出,addrlen指定其大小。對於sendmsg(),目的地址由msg.msg_name給出,msg.msg_namelen指定其大小。
對於send()和sendto(),消息位於buf中,長度為len。對於sendmsg(),消息存儲在msg.msg_iov元素指向的數組數據區(見下文)。sendmsg()調用還允許發送輔助數據(也稱為控制信息)。
如果消息太長,無法通過底層協議自動傳遞,則會返回錯誤EMSGSIZE,並且消息不會被傳輸。
send()中沒有隱含傳遞失敗的指示。本地檢測到的錯誤由返回值-1表示。
當消息不適合套接字的發送緩沖區時,send()通常會阻塞,除非套接字已被置於非阻塞I/O模式。在這種情況下,它將在非阻塞模式下失敗,並顯示錯誤EAGAIN或EWOULDBLOCK。select(2)調用可用於確定何時可以發送更多數據。
上面的描述還是很籠統的。以TCP為例。按照我的理解,我認為只要發送緩沖區有空閑位置,協議棧此時沒有向網絡發送數據,就可以寫入。對於阻塞模式,它將返回,直到所有數據都寫入緩沖區,否則它將壹直被阻塞。對於非阻塞模式,有壹個由SO_SNDTIMEO選項控制的超時。詳見插座(7)。如果有空閑位置要發送,也就是目前可以寫入,那麽就寫入緩沖區,然後返回成功寫入的字節數。如果超時時沒有數據寫入,或者當前未寫入,則返回-1,並將errno設置為EAGAIN或EWOULDBLOCK。
flags參數是零個或多個以下標誌的按位OR。
sendmsg()使用的msghdr結構定義如下:
對於未連接套接字msg_name,指定數據報的目的地址,指向包含該地址的緩沖區;msg_namelen字段應設置為地址大小。對於連接的套接字,這些字段應該分別指定為NULL和0。這裏,未連接是指數據報協議,連接是指數據流協議。
與writev(2)壹樣,msg_iov和msg_iovlen字段指定分散-聚集位置。
Msg_iov是壹個緩沖數組:
使用msg_control和msg_controllen成員發送控制信息(輔助數據)。內核可以處理的每個套接字的最大控制緩沖區長度受到/proc/sys/net/core/optmem_max中的值的限制;參見插座(7)。有關在各種套接字域中使用輔助數據的更多信息,請參見unix(7)和ip(7)。
Msg_flags字段被忽略。
成功時,返回成功發送的字節數,這不壹定與我們的緩沖區大小相同。發生錯誤時,將返回-1,並設置errno來指示該錯誤。
這些是套接字層產生的壹些標準錯誤。底層協議模塊可能產生並返回額外的錯誤;請參考各自的手冊頁。
4.4BSD,SVr4,POSIX.1-2001。這些接口最早出現在4.2BSD中。
POSIX.1-2001僅描述了MSG_OOB和MSG_EOR標誌。POSIX.1-2008增加了MSG_NOSIGNAL的規範。MSG_CONFIRM標誌是壹個Linux擴展。
根據POSIX.1-2001,msghdr結構的msg_controllen字段應該是socklen_t類型,msg_iovlen字段應該是int類型,但glibc目前將兩者都視為size _ T..
有關可用於在單個調用中傳輸多個數據報的特定於Linux的系統調用的信息,請參見sendmmsg(2)。
Linux可能會返回EPIPE而不是ENOTCONN。
getaddrinfo(3)中顯示了壹個使用send()的示例。