Linux Socket 详解

张开发
2026/4/11 3:45:12 15 分钟阅读

分享文章

Linux Socket 详解
1. 基本架构Linux Socket 实现基于 BSD Socket 接口采用分层设计用户空间接口层提供标准 Socket API内核协议无关层通用 Socket 操作和管理协议族实现层具体协议实现TCP/IP、UDP等设备驱动层网络硬件接口2. 核心数据结构struct socketstructsocket{socket_state state;// Socket 状态shorttype;// Socket 类型 (SOCK_STREAM, SOCK_DGRAM)conststructproto_ops*ops;// 协议操作函数表structfile*file;// 关联的文件描述符structsock*sk;// 指向底层网络层的 sock 结构// ... 其他字段};struct sockstructsock{structsock_common__sk_common;// 通用 sock 信息unsignedintsk_state_change:2;// 状态变化回调unsignedintsk_write_seq;// 写序列号// ... 大量协议相关的字段};3. 系统调用实现socket() 系统调用SYSCALL_DEFINE3(socket,int,family,int,type,int,protocol){intretval;structsocket*sock;// 分配 socket 结构retvalsock_create(family,type,protocol,sock);if(retval0)gotoout;// 安装到文件描述符表retvalsock_map_fd(sock,flags(O_CLOEXEC|O_NONBLOCK));if(retval0)gotoout_release;returnretval;}bind() 系统调用SYSCALL_DEFINE3(bind,int,fd,structsockaddr__user*,umyaddr,int,addrlen){structsocket*sock;structsockaddr_storageaddress;interr,fput_needed;// 获取 socket 对象socksockfd_lookup_light(fd,err,fput_needed);if(sock){// 复制用户空间地址errmove_addr_to_kernel(umyaddr,addrlen,address);if(!err)// 调用协议特定的 bind 实现errsock-ops-bind(sock,(structsockaddr*)address,addrlen);fput_light(sock-file,fput_needed);}returnerr;}4. 协议操作接口proto_ops 结构structproto_ops{int(*release)(structsocket*sock);// 释放 socketint(*bind)(structsocket*sock,structsockaddr*myaddr,intsockaddr_len);// 绑定地址int(*connect)(structsocket*sock,structsockaddr*vaddr,intsockaddr_len,intflags);// 连接int(*socketpair)(structsocket*sock1,structsocket*sock2);// 创建 socket 对int(*accept)(structsocket*sock,structsocket*newsock,intflags,bool kern);// 接受连接int(*getname)(structsocket*sock,structsockaddr*addr,intpeer);// 获取地址信息unsignedint(*poll)(structfile*file,structsocket*sock,poll_table*wait);// 轮询int(*ioctl)(structsocket*sock,unsignedintcmd,unsignedlongarg);// 控制操作int(*listen)(structsocket*sock,intlen);// 监听int(*shutdown)(structsocket*sock,intflags);// 关闭int(*setsockopt)(structsocket*sock,intlevel,intoptname,char__user*optval,unsignedintoptlen);// 设置选项int(*getsockopt)(structsocket*sock,intlevel,intoptname,char__user*optval,int__user*optlen);// 获取选项int(*sendmsg)(structsocket*sock,structmsghdr*m,size_ttotal_len);// 发送消息int(*recvmsg)(structsocket*sock,structmsghdr*m,size_ttotal_len,intflags);// 接收消息// ... 更多操作函数指针};5. TCP 协议实现tcp_prot 协议结构structprototcp_prot{.nameTCP,.ownerTHIS_MODULE,.closetcp_close,.connecttcp_v4_connect,.disconnecttcp_disconnect,.acceptinet_csk_accept,.ioctltcp_ioctl,.inittcp_v4_init_sock,.destroytcp_v4_destroy_sock,.shutdowntcp_shutdown,.setsockopttcp_setsockopt,.getsockopttcp_getsockopt,.sendmsgtcp_sendmsg,.recvmsgtcp_recvmsg,// ... 更多 TCP 特定函数};三次握手实现// 客户端连接inttcp_v4_connect(structsock*sk,structsockaddr*uaddr,intaddr_len){// 设置目标地址// 发送 SYN 包// 等待服务器响应// 完成三次握手}// 服务器接受连接structsock*inet_csk_accept(structsock*sk,intflags,int*err,bool kern){structinet_connection_request*req;structsock*newsk;// 从已完成连接队列中取出连接reqreqsk_queue_remove(icsk-icsk_accept_queue);if(!req)returnERR_PTR(-EAGAIN);// 创建新的 socket 结构newsktcp_create_openreq_child(sk,req,skb);// ... 初始化新连接returnnewsk;}6. 数据传输机制sendmsg 实现inttcp_sendmsg(structkiocb*iocb,structsocket*sock,structmsghdr*msg,size_tsize){structsock*sksock-sk;structsk_buff*skb;interr,copied0;lock_sock(sk);while(copiedsize){// 分配 sk_buff 缓冲区skballoc_skb(size,GFP_KERNEL);if(!skb){err-ENOMEM;break;}// 将数据拷贝到缓冲区skb_put(skb,copy);// 添加到发送队列tcp_queue_skb(sk,skb);copiedcopy;}// 触发数据发送tcp_push(sk,MSG_NOSIGNAL,size,tp-mss_cache,flags);release_sock(sk);returncopied;}recvmsg 实现inttcp_recvmsg(structkiocb*iocb,structsock*sk,structmsghdr*msg,size_tlen,intnonblock,intflags,int*addr_len){structsk_buff*skb;intcopied,err;lock_sock(sk);while(copiedlen){// 从接收队列中获取数据skbskb_peek(sk-sk_receive_queue);if(!skb){// 如果没有数据且是非阻塞模式返回错误if(nonblock){err-EAGAIN;break;}// 否则等待数据到达tcp_wait_data(sk,timeo);continue;}// 从 sk_buff 中拷贝数据到用户空间copiedskb_copy_datagram_iovec(skb,offset,msg-msg_iov,chunk);}release_sock(sk);returncopied;}7. 内核网络栈处理网络包接收处理// 网络设备驱动接收数据包intnetif_rx(structsk_buff*skb){// 将数据包放入接收队列// 触发软中断处理returnnetif_rx_internal(skb);}// 网络层处理intip_rcv(structsk_buff*skb,structnet_device*dev,structpacket_type*pt,structnet_device*orig_dev){structiphdr*iph;// IP 头部处理iphip_hdr(skb);// 根据协议类型分发到上层switch(iph-protocol){caseIPPROTO_TCP:tcp_v4_rcv(skb);break;caseIPPROTO_UDP:udp_rcv(skb);break;}returnNET_RX_SUCCESS;}// TCP 层处理inttcp_v4_rcv(structsk_buff*skb){structtcphdr*th;structsock*sk;// 查找对应的 socketsk__tcp_v4_lookup(skb);if(!sk){// 如果找不到对应 socket发送 RSTtcp_v4_send_reset(skb);gotodiscard_it;}// 将数据包传递给 socket 处理returntcp_rcv_established(sk,skb);}8. 内存管理sk_buff 结构structsk_buff{union{struct{structsk_buff*next;// 链表指针structsk_buff*prev;};};structnet_device*dev;// 接收/发送设备unsignedintlen;// 数据包长度unsignedintdata_len;// 分片数据长度__u16 mac_len;// MAC 头部长度skb_frag_t*frags;// 分片数组structsk_buff*frag_list;// 分片链表structsock*sk;// 关联的 socketcharcb[48]__aligned(8);// 控制块unsignedlong_skb_refdst;// 目标缓存// ... 更多字段};9. 并发控制锁机制// Socket 锁操作staticinlinevoidlock_sock(structsock*sk){bh_lock_sock(sk);}staticinlinevoidrelease_sock(structsock*sk){bh_unlock_sock(sk);}// 网络命名空间锁voidnet_lock(void){rcu_read_lock();}voidnet_unlock(void){rcu_read_unlock();}10. 性能优化零拷贝技术// 使用 sendfile 实现零拷贝ssize_tdo_sendfile(intout_fd,intin_fd,loff_t*ppos,size_tcount,loff_tmax){// 直接在内核空间传输数据避免用户空间拷贝returnsplice_direct_to_actor(...);}// 使用 mmap 和 write 实现共享内存传输void*mappedmmap(NULL,size,PROT_READ,MAP_SHARED,fd,0);write(sock_fd,mapped,size);缓冲区管理// SLAB 分配器优化 sk_buff 分配structkmem_cache*skbuff_head_cache __read_mostly;structkmem_cache*skbuff_fclone_cache __read_mostly;staticstructsk_buff*alloc_skb(unsignedintsize,gfp_tpriority){// 使用专用的 slab 缓存分配 sk_buffreturn__alloc_skb(size,priority,0,NUMA_NO_NODE);}Linux Socket 实现充分利用了操作系统内核的各种机制包括内存管理、并发控制、中断处理等为用户空间应用程序提供了高效、可靠的网络通信能力。

更多文章