【C/C++】手写 DPDK 协议栈(六):TCP 三次握手、状态机与数据回显

【C/C++】手写 DPDK 协议栈(六):TCP 三次握手、状态机与数据回显
目录手写 DPDK 协议栈六TCP 三次握手、状态机与数据回显1. 状态机是 TCP 的核心2. 三次握手的数字关系3. 建连与数据投递4. 实验抓包小结手写 DPDK 协议栈六TCP 三次握手、状态机与数据回显标签DPDKTCP状态机用户态网络栈tcp/stack.c与tcp/socket.c在 UDP 的 socket/ring 框架上加入 TCP 状态、序列号、确认号与标志位。它的目标是教学型最小 TCP 服务端而不是完整 RFC 实现。1. 状态机是 TCP 的核心LISTEN --SYN-- SYN_RECEIVED --ACK-- ESTABLISHED ESTABLISHED --FIN-- CLOSE_WAIT --close-- LAST_ACK --ACK-- CLOSED课程socket_block_t保存tcp_status、seq_num、ack_num和window_size接收路径按四元组/五元组找到连接再按状态调用处理函数。switch(local-tcp_status){caseTCP_STATUS_LISTEN:tcp_listen_handle(local,ip_hdr);break;caseTCP_STATUS_SYN_RECEIVED:tcp_syn_received_handle(local,ip_hdr);break;caseTCP_STATUS_ESTABLISHED:tcp_established_handle(local,ip_hdr);break;caseTCP_STATUS_LAST_ACK:tcp_last_ack_handle(local,ip_hdr);break;default:break;}2. 三次握手的数字关系Client Server SYN, seqx - LISTEN - SYNACK, seqy, ackx1 ACK, seqx1, acky1 - ESTABLISHEDSYN 和 FIN 各消耗一个序列号纯 ACK 不消耗序列号。TCP 头长来自data_off高 4 位再乘 4应用数据长度为 IP 总长减去 IP 头与 TCP 头长度。3. 建连与数据投递收到 LISTEN socket 的 SYN 时课程代码封装 SYNACK 到监听 socket 的outring同时按对端地址创建一个新socket_block_t状态置为SYN_RECEIVED。第三次 ACK 到达后改为ESTABLISHED。if(tcphdr-tcp_flagsRTE_TCP_PSH_FLAG){uint16_thdr_len(tcphdr-data_off4)*4;uint16_tpayload_lenntohs(ip_hdr-total_length)-sizeof(structrte_ipv4_hdr)-hdr_len;local-ack_numntohl(tcphdr-sent_seq)payload_len;/* 一个 ACK 入 out ring携带 payload 的副本入 in ring */}数据到达时先排队 ACK再将 payload 投递给应用能让“确认网络数据”和“业务处理”解耦。4. 实验抓包这个版本适合作为 TCP 状态机起点但尚未覆盖重传定时器、滑动窗口、乱序重组、拥塞控制、TIME_WAIT 管理、RST、MSS/窗口缩放协商和完整校验。任何外网服务都不能直接使用该简化实现。小结手写 TCP 最有价值的部分不在“拼出一个 SYNACK”而在于把每个输入报文映射为明确状态转移、序列号更新和应用可见事件。下一篇把单循环拆成三层解决协议栈逐步复杂后的耦合问题。