当前位置: 首页 > news >正文

Linux Socket 详解

1. 基本架构

Linux Socket 实现基于 BSD Socket 接口,采用分层设计:

  • 用户空间接口层:提供标准 Socket API
  • 内核协议无关层:通用 Socket 操作和管理
  • 协议族实现层:具体协议实现(TCP/IP、UDP等)
  • 设备驱动层:网络硬件接口

2. 核心数据结构

struct socket

structsocket{socket_state state;// Socket 状态shorttype;// Socket 类型 (SOCK_STREAM, SOCK_DGRAM)conststructproto_ops*ops;// 协议操作函数表structfile*file;// 关联的文件描述符structsock*sk;// 指向底层网络层的 sock 结构// ... 其他字段};

struct sock

structsock{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 结构retval=sock_create(family,type,protocol,&sock);if(retval<0)gotoout;// 安装到文件描述符表retval=sock_map_fd(sock,flags&(O_CLOEXEC|O_NONBLOCK));if(retval<0)gotoout_release;returnretval;}

bind() 系统调用

SYSCALL_DEFINE3(bind,int,fd,structsockaddr__user*,umyaddr,int,addrlen){structsocket*sock;structsockaddr_storageaddress;interr,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,(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={.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(structsock*sk,structsockaddr*uaddr,intaddr_len){// 设置目标地址// 发送 SYN 包// 等待服务器响应// 完成三次握手}// 服务器接受连接structsock*inet_csk_accept(structsock*sk,intflags,int*err,bool kern){structinet_connection_request*req;structsock*newsk;// 从已完成连接队列中取出连接req=reqsk_queue_remove(&icsk->icsk_accept_queue);if(!req)returnERR_PTR(-EAGAIN);// 创建新的 socket 结构newsk=tcp_create_openreq_child(sk,req,skb);// ... 初始化新连接returnnewsk;}

6. 数据传输机制

sendmsg 实现

inttcp_sendmsg(structkiocb*iocb,structsocket*sock,structmsghdr*msg,size_tsize){structsock*sk=sock->sk;structsk_buff*skb;interr,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);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(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);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 头部处理iph=ip_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*mapped=mmap(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 实现充分利用了操作系统内核的各种机制,包括内存管理、并发控制、中断处理等,为用户空间应用程序提供了高效、可靠的网络通信能力。

http://www.jsqmd.com/news/621486/

相关文章:

  • Z-Image-GGUF惊艳效果:负向提示词精准过滤水印/文字/畸变的真实案例
  • 【Python实战解析】从数据采集到模型预测:一个完整天气数据分析项目的技术实现
  • WindNerd Core:基于磁传感的低功耗风速风向传感器设计
  • Redis如何批量更新用户信息_基于HMSET指令实现Hash多字段修改
  • 从医学分割到AI绘画:UNet架构如何成为DDPM等扩散模型的‘心脏’?
  • Flutter Riverpod 2.5.1 保姆级避坑指南:从购物车实战到异步状态刷新,手把手教你避开那些文档里没写的坑
  • 2026年软件测试薪资全景报告:城市与行业深度对比
  • JPlag代码抄袭检测技术架构深度剖析:3大算法实现与20+语言支持机制
  • MouseTo库:Arduino实现绝对坐标鼠标控制
  • Notepad++深度解析:免费开源轻量高效的程序员必备代码编辑器
  • Rhino_IT嵌入式语音意图识别引擎深度解析
  • FireRedASR-AED-L效果惊艳:中英术语缩写(如IoT、SaaS、CRM)精准识别
  • 从PyTorch的MKL依赖冲突,聊聊Conda和Pip安装包背后的‘静动态链接’选择
  • 嵌入式轻量级JSON解析库json_lite设计与应用
  • OfficeToPDF终极指南:5分钟掌握服务器级文档自动化转换神器
  • 利用闲置板卡体验飞牛NAS
  • 塑胶产品结构设计查询软件
  • Claude仅用10分钟发现Apache ActiveMQ潜伏13年的RCE漏洞
  • 世毫九实验室Alpha-9认知生存代码(仅演示)
  • 高效搜索语法实战指南:从基础到进阶
  • 验证自己的处理器(二) —— 运行CoreMark
  • 自动驾驶中的‘状态估计’利器:深入浅出图解无迹卡尔曼滤波(UKF)
  • DeepSeek-R1-Distill-Qwen-1.5B真实落地案例:教育行业习题解析系统搭建
  • 2024最新三星固件下载工具完全指南:跨平台免费开源解决方案
  • 别再用裸奔的mysqldump了!MySQL 5.7+安全备份的三种进阶姿势
  • 如何处理SQL注入敏感源_记录所有不安全的SQL请求
  • 5分钟掌握显微图像拼接:MIST工具如何彻底改变科研图像处理
  • 卫星互联网与太空计算:最后的云端 frontier
  • CoDeF视频处理革命:从静态图像到动态视频的完美跨越
  • Qwen-Image-2512-Pixel-Art-LoRA惊艳效果实测:同一提示词下不同LoRA强度风格对比