1. 基本架构
Linux Socket 实现基于 BSD Socket 接口,采用分层设计:
- 用户空间接口层
- 内核协议无关层
- 协议族实现层
- 设备驱动层
2. 核心数据结构
struct socket
struct socket { socket_state state; // Socket 状态 short type; // Socket 类型 (SOCK_STREAM, SOCK_DGRAM) const struct proto_ops *ops; // 协议操作函数表 struct file *file; // 关联的文件描述符 struct sock *sk; // 指向底层网络层的 sock 结构 // ... 其他字段};
struct sock
struct sock { struct sock_common __sk_common; // 通用 sock 信息 unsigned int sk_state_change:2; // 状态变化回调 unsigned int sk_write_seq; // 写序列号 // ... 大量协议相关的字段};
3. 系统调用实现
socket() 系统调用
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol){ int retval; struct socket *sock; // 分配 socket 结构 retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out; // 安装到文件描述符表 retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); if (retval < 0) goto out_release; return retval;}
bind() 系统调用
SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen){ struct socket *sock; struct sockaddr_storage address; int err, fput_needed; // 获取 socket 对象 sock = sockfd_lookup_light(fd, &err, &fput_needed); if (sock) { // 复制用户空间地址 err = move_addr_to_kernel(umyaddr, addrlen, &address); if (!err) // 调用协议特定的 bind 实现 err = sock->ops->bind(sock, (struct sockaddr *)&address, addrlen); fput_light(sock->file, fput_needed); } return err;}
4. 协议操作接口
proto_ops 结构
struct proto_ops { int (*release)(struct socket *sock); // 释放 socket int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len); // 绑定地址 int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags); // 连接 int (*socketpair)(struct socket *sock1, struct socket *sock2); // 创建 socket 对 int (*accept)(struct socket *sock, struct socket *newsock, int flags, bool kern); // 接受连接 int (*getname)(struct socket *sock, struct sockaddr *addr, int peer); // 获取地址信息 unsignedint(*poll)(struct file *file, struct socket *sock, poll_table *wait); // 轮询 int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg); // 控制操作 int (*listen)(struct socket *sock, int len); // 监听 int (*shutdown)(struct socket *sock, int flags); // 关闭 int (*setsockopt)(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen); // 设置选项 int (*getsockopt)(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen); // 获取选项 int (*sendmsg)(struct socket *sock, struct msghdr *m, size_t total_len); // 发送消息 int (*recvmsg)(struct socket *sock, struct msghdr *m, size_t total_len, int flags); // 接收消息 // ... 更多操作函数指针};
5. TCP 协议实现
tcp_prot 协议结构
struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, .close = tcp_close, .connect = tcp_v4_connect, .disconnect = tcp_disconnect, .accept = inet_csk_accept, .ioctl = tcp_ioctl, .init = tcp_v4_init_sock, .destroy = tcp_v4_destroy_sock, .shutdown = tcp_shutdown, .setsockopt = tcp_setsockopt, .getsockopt = tcp_getsockopt, .sendmsg = tcp_sendmsg, .recvmsg = tcp_recvmsg, // ... 更多 TCP 特定函数};
三次握手实现
// 客户端连接inttcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len){ // 设置目标地址 // 发送 SYN 包 // 等待服务器响应 // 完成三次握手}// 服务器接受连接struct sock *inet_csk_accept(struct sock *sk, int flags, int *err, bool kern){ struct inet_connection_request *req; struct sock *newsk; // 从已完成连接队列中取出连接 req = reqsk_queue_remove(&icsk->icsk_accept_queue); if (!req) return ERR_PTR(-EAGAIN); // 创建新的 socket 结构 newsk = tcp_create_openreq_child(sk, req, skb); // ... 初始化新连接 return newsk;}
6. 数据传输机制
sendmsg 实现
inttcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size){ struct sock *sk = sock->sk; struct sk_buff *skb; int err, copied = 0; lock_sock(sk); while (copied < size) { // 分配 sk_buff 缓冲区 skb = alloc_skb(size, GFP_KERNEL); if (!skb) { err = -ENOMEM; break; } // 将数据拷贝到缓冲区 skb_put(skb, copy); // 添加到发送队列 tcp_queue_skb(sk, skb); copied += copy; } // 触发数据发送 tcp_push(sk, MSG_NOSIGNAL, size, tp->mss_cache, flags); release_sock(sk); return copied;}
recvmsg 实现
inttcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int nonblock, int flags, int *addr_len){ struct sk_buff *skb; int copied, err; lock_sock(sk); while (copied < len) { // 从接收队列中获取数据 skb = skb_peek(&sk->sk_receive_queue); if (!skb) { // 如果没有数据且是非阻塞模式,返回错误 if (nonblock) { err = -EAGAIN; break; } // 否则等待数据到达 tcp_wait_data(sk, &timeo); continue; } // 从 sk_buff 中拷贝数据到用户空间 copied += skb_copy_datagram_iovec(skb, offset, msg->msg_iov, chunk); } release_sock(sk); return copied;}
7. 内核网络栈处理
网络包接收处理
// 网络设备驱动接收数据包intnetif_rx(struct sk_buff *skb){ // 将数据包放入接收队列 // 触发软中断处理 return netif_rx_internal(skb);}// 网络层处理intip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev){ struct iphdr *iph; // IP 头部处理 iph = ip_hdr(skb); // 根据协议类型分发到上层 switch (iph->protocol) { case IPPROTO_TCP: tcp_v4_rcv(skb); break; case IPPROTO_UDP: udp_rcv(skb); break; } return NET_RX_SUCCESS;}// TCP 层处理inttcp_v4_rcv(struct sk_buff *skb){ struct tcphdr *th; struct sock *sk; // 查找对应的 socket sk = __tcp_v4_lookup(skb); if (!sk) { // 如果找不到对应 socket,发送 RST tcp_v4_send_reset(skb); goto discard_it; } // 将数据包传递给 socket 处理 return tcp_rcv_established(sk, skb);}
8. 内存管理
sk_buff 结构
struct sk_buff { union { struct { struct sk_buff *next; // 链表指针 struct sk_buff *prev; }; }; struct net_device *dev; // 接收/发送设备 unsigned int len; // 数据包长度 unsigned int data_len; // 分片数据长度 __u16 mac_len; // MAC 头部长度 skb_frag_t *frags; // 分片数组 struct sk_buff *frag_list; // 分片链表 struct sock *sk; // 关联的 socket char cb[48] __aligned(8); // 控制块 unsigned long _skb_refdst; // 目标缓存 // ... 更多字段};
9. 并发控制
锁机制
// Socket 锁操作static inline void lock_sock(struct sock *sk){ bh_lock_sock(sk);}static inline void release_sock(struct sock *sk){ bh_unlock_sock(sk);}// 网络命名空间锁void net_lock(void){ rcu_read_lock();}void net_unlock(void){ rcu_read_unlock();}
10. 性能优化
零拷贝技术
// 使用 sendfile 实现零拷贝ssize_tdo_sendfile(int out_fd, int in_fd, loff_t *ppos, size_t count, loff_t max){ // 直接在内核空间传输数据,避免用户空间拷贝 return splice_direct_to_actor(...);}// 使用 mmap 和 write 实现共享内存传输void *mapped = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);write(sock_fd, mapped, size);
缓冲区管理
// SLAB 分配器优化 sk_buff 分配struct kmem_cache *skbuff_head_cache __read_mostly;struct kmem_cache *skbuff_fclone_cache __read_mostly;static struct sk_buff *alloc_skb(unsigned int size, gfp_t priority){ // 使用专用的 slab 缓存分配 sk_buff return __alloc_skb(size, priority, 0, NUMA_NO_NODE);}
Linux Socket 实现充分利用了操作系统内核的各种机制,包括内存管理、并发控制、中断处理等,为用户空间应用程序提供了高效、可靠的网络通信能力。