基於 Linux 3.15.2 內核源碼,從用戶態 send() 系統調用入手,追蹤數據如何流經 Socket 層進入 TCP 協議棧。掌握此流程對網絡調優、零拷貝理解、內核旁路技術研發至關重要。

struct socket:用戶態文件描述符對應的內核對象,持有 struct sock *sk 指向協議層對象。struct sock:協議無關的核心對象,TCP 對應 struct tcp_sock。struct proto_ops:Socket 操作函數表,inet_stream_ops.sendmsg = inet_sendmsg。
write/send/sendto/sendmsg/sendmmsg 系統調用差異僅在參數組裝,最終均匯聚至 sock_sendmsg() → inet_sendmsg() → tcp_sendmsg()。
// 消息頭:描述分散/聚集 I/O、目標地址、控制數據
struct msghdr {
void *msg_name; // 目標地址 (sendto 用)
socklen_t msg_namelen;
struct iovec *msg_iov; // 數據塊數組 (scatter/gather)
size_t msg_iovlen; // 數據塊個數
void *msg_control; // 輔助數據 (如文件描述符傳遞)
socklen_t msg_controllen;
int msg_flags;
};
struct iovec {
void *iov_base; // 數據指針
size_t iov_len; // 數據長度
};
阻塞/非阻塞由 O_NONBLOCK 或 MSG_DONTWAIT 控制。
所有 Socket 系統調用統一入口 sys_socketcall(int call, unsigned long *args),根據 call 分發:
case SYS_SEND: return sys_send(a0, a1, a2, a3); case SYS_SENDTO: return sys_sendto(a0, a1, a2, a3, a4, a5); case SYS_SENDMSG: return sys_sendmsg(a0, a1, a2); case SYS_SENDMMSG: return sys_sendmmsg(a0, a1, a2, a3);
msghdr,拷貝用戶態地址/數據,調用 sock_sendmsg()。kiocb (AIO 控制塊),調用 __sock_sendmsg()。sock_iocb,調用 sock->ops->sendmsg() 即 inet_sendmsg()。sk->sk_prot->sendmsg() 即 tcp_sendmsg() 進入 TCP 層。
// AIO 控制塊
struct kiocb {
struct file *ki_filp;
struct kioctx *ki_ctx; // 同步操作時為 NULL
void *private; // 指向 sock_iocb
struct task_struct *tsk; // 執行 I/O 的進程
// ...
};
// Socket 專用 AIO 信息
struct sock_iocb {
struct socket *sock;
struct msghdr *msg;
size_t size;
// ...
};
將深入 TCP 層 tcp_sendmsg():發送緩衝區管理、MSS 計算、Nagle 算法、零拷貝 sendfile/splice 實現、拥塞控制入口等。