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