在Socket編程中,發送數據報文可供使用的API函數有send,sendto和sendmsg,下面是關于前兩個系統調用的原型:
#include <sys/socket.h>
ssize_t send( int socket, const void *buffer, size_t length, int flags );
    
   請注意它的返回值的類型ssize_t,其含義是signed size。從內核代碼中,我們可以看到,在32位系統上,它是int,在64位系統上,它是long。它常用于表示在某一次操作后,緩沖區中可以被讀或寫的字節數量。相對應的,還有一個數據類型size_t,其含義是unsigned size。常用于表示對象本身的大小,操作sizeof的返回值就是該類型,malloc,memcpy等函數的參數中用該類型表示對象的大小,在32位系統上,它是unsigned int,在64位系統上,它是unsigned long。
     send執行成功,會返回被發送出去的數據報文的字節數,如果執行失敗,則會返回-1(所以不能返回size_t類型),并且可以從errno上查找到錯誤原因。
#include <sys/socket.h>
ssize_t sendto(int socket, const void *message, size_t length,
                 int flags, const struct sockaddr *dest_addr,
                  socklen_t dest_len);
在內核的實現中,send和sendto系統調用最終都會調用到內核函數:
asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,
       struct sockaddr __user *addr, int addr_len)
    
    在send系統調用中,參數addr被置為NULL,addr_len為0。sys_sendto首先根據傳入的描述符fd,找到對應的struct socket結構體。然后構建內核的消息結構struct msghdr:
struct msghdr {
   void * msg_name;
   int   msg_namelen;
   struct iovec * msg_iov;
   __kernel_size_t msg_iovlen;
   void   * msg_control;
   __kernel_size_t msg_controllen;
   unsigned msg_flags;
};
    
   msg_name和msg_namelen就是數據報文要發向的對端的地址信息(即sendto系統調用中的addr和addr_len)。當使用send時,它們的值為NULL和0。msg_iov的定義如下:
struct iovec
{
   void __user *iov_base;
   __kernel_size_t iov_len;
};
  
   表示存放待發送數據的一個緩沖區,iov_base是緩沖區的起始地址,指向message, iov_len是緩沖區的長度,指向length。msg_iovlen是緩沖區的數量,對于sendto和send來講,msg_iovlen都是1。 msg_flags即為傳入的參數flags,現在暫時不過多的關注flags的應用。msg_control和msg_controllen暫時不關注。
    
   sys_sendto構建完這些后,調用sock_sendmsg繼續執行發送流程,傳入參數為struct msghdr和數據的長度。忽略中間的一些不重要的細節,sock_sendmsg繼續調用__sock_sendmsg,__sock_sendmsg 最后調用struct socket->ops->sendmsg,即對應套接字類型的sendmsg函數,所有的套接字類型的sendmsg函數都是 inet_sendmsg,該函數首先檢查本地端口是否已綁定,無綁定則執行自動綁定,而后調用具體協議的sendmsg函數。
   
  下面再來看sendmsg系統調用:
#include <sys/socket.h>
ssize_t sendmsg(int socket, const struct msghdr *message, int flags);
    
可以看到,它跟send和sendto的最大區別就是struc msghdr由用戶來構建完成,對應的內核處理函數是sys_sendmsg。

原文出處http://hi.baidu.com/linux_kernel/blog/item/dfae34fa638927889e51468a.html