一、dpdk之tcp代码案例
1.tcp.c
cpp
#include <stdio.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>
#include <sys/time.h> // 用于计算Ping耗时
#include <rte_eal.h>
#include <rte_mbuf.h>
#include <rte_ethdev.h>
#include <rte_mempool.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_udp.h>
#include <rte_arp.h>
#include <rte_net.h>
#include <rte_cycles.h>
#include <rte_icmp.h> // DPDK ICMP头定义
#include <rte_tcp.h>
#define ENABLE_ARP 1
#define NUM_MBUFS 4096
#define BURST_SIZE 128
#define ENABLE_SEND 1
// ARP表相关配置
#define ARP_TABLE_MAX_ENTRY 64 // ARP表最大条目数
#define ARP_ENTRY_EXPIRE_SEC 300 // ARP条目过期时间(5分钟)
#define ARP_REQUEST_INTERVAL 1 // ARP请求发送间隔
#define ARP_REQUEST_RETRY 3 // ARP请求的重试次数
// ICMP相关配置
#define ICMP_ECHO_DATA_LEN 56 // ICMP回显数据长度(标准Ping包)
#define ICMP_REQUEST_RETRY 4 // Ping重试次数
#define ICMP_REQUEST_TIMEOUT 1 // Ping超时时间(秒)
#define ICMP_ID 0x1234 // ICMP标识符(固定值)
// tcp相关配置
#define TCP_TABLE_MAX_ENTRY 32 // tcp连接表最大条目数
#define TCP_SYN_RETRY 3 // SYN重传次数
#define TCP_SYN_TIMEOUT 3 // SYN超时时间
#define TCP_MSS 1460 // TCP最大分段大小
#define TCP_WINDOW_SIZE 65535 // TCP窗口大小
#define TCP_TTL 64 // TCP ttl
#define TCP_CONN_EXPIRE_SEC 60 // TCP连接过期时间(60秒)
#define TCP_CLOSED_CLEAN_INTERVAL 10 // 清理CLOSED状态条目的间隔(10秒)
#define TCP_TABLE_SIZE TCP_TABLE_MAX_ENTRY // 根据你的实际定义调整
#define TCP_TIME_WAIT_TIMEOUT 60 // 60秒清理TIME_WAIT
#define TCP_SYN_RECV_TIMEOUT 10 // 10秒清理SYN_RECV半连接
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
// 全局端口配置
int global_portid = 0;
static struct rte_ether_addr gPortMacAddr; // 本地MAC
static u32 gPortIpAddr = 0; // 本地IP
static int g_running = 1; // 程序运行标志
// MBUF池全局指针
struct rte_mempool *g_mbuf_pool = NULL;
//ICMP ping上下文,用于主动Ping时记录请求信息
typedef struct {
u32 target_ip; //目标ip
u16 seq; //序列号
struct timeval send_time; //发送时间
int recv_flag; //是否收到响应
double rtt; //往返时间
}icmp_ping_ctx_t;
// 全局Ping上下文(线程安全)
static icmp_ping_ctx_t g_ping_ctx;
static pthread_mutex_t g_ping_mutex = PTHREAD_MUTEX_INITIALIZER;
// ARP表条目结构体
typedef struct {
u32 ip_addr; // 目标IP地址
struct rte_ether_addr mac; // 目标MAC地址
time_t update_time; // 最后更新时间
int valid; // 条目是否有效,1有效,0无效
} arp_table_entry_t;
// ARP表结构体
typedef struct {
arp_table_entry_t entries[ARP_TABLE_MAX_ENTRY];
pthread_mutex_t mutex;
} arp_table_t;
arp_table_t g_arp_table; // 全局ARP表
//TCP连接状态枚举
typedef enum {
TCP_STATE_CLOSED = 0,
TCP_STATE_SYN_SENT,
TCP_STATE_ESTABLISHED,
TCP_STATE_FIN_WAIT1,
TCP_STATE_FIN_WAIT2,
TCP_STATE_CLOSING,
TCP_STATE_TIME_WAIT,
TCP_STATE_LISTEN,
TCP_STATE_SYN_RECV
}tcp_state_t;
// TCP连接条目结构体(新增接收缓冲区处理粘包/乱序)
typedef struct {
uint32_t src_ip; // 源IP
uint32_t dst_ip; // 目标IP
uint16_t src_port; // 源端口
uint16_t dst_port; // 目标端口
tcp_state_t state; // 连接状态
uint32_t seq; // 发送序列号
uint32_t ack; // 确认序列号
time_t last_active; // 最后活动时间
int valid; // 条目是否有效
// 新增:接收缓冲区(处理粘包/乱序)
uint8_t recv_buf[4096]; // 接收缓存
uint32_t recv_buf_len; // 缓存数据长度
uint32_t recv_next_seq; // 期望接收的下一个seq
} tcp_conn_entry_t;
//tcp连接表
typedef struct {
tcp_conn_entry_t entries[TCP_TABLE_MAX_ENTRY];
pthread_mutex_t mutex;
}tcp_table_t;
tcp_table_t g_tcp_table; // 全局TCP连接表
// ====================== 函数前置声明 ======================
static void arp_table_init(void);
static int arp_table_lookup(u32 ip_addr, struct rte_ether_addr *mac);
static int send_arp_request(u32 target_ip);
static int ustack_encode_arp_request(u8 *msg, u32 target_ip);
static int encode_icmp_echo_request(u8 *msg, u32 dip, u16 seq);
static int send_icmp_echo_request(u32 dip, u16 seq);
static void handle_icmp_echo_reply(struct rte_icmp_hdr *icmphdr, struct rte_ipv4_hdr *iphdr);
static void handle_udp_packet(__attribute__((unused))struct rte_ether_hdr *ethhdr, struct rte_ipv4_hdr *iphdr, struct rte_udp_hdr *udphdr);
// TCP相关函数声明
static void tcp_table_init(void);
static void tcp_table_clean_invalid(void);
static void tcp_table_clean_invalid(void);
static int tcp_table_reset_entry(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port);
static uint16_t tcp_checksum(struct rte_ipv4_hdr *ip, struct rte_tcp_hdr *tcp, uint16_t tcp_len);
static int encode_tcp_packet(uint8_t *msg, struct rte_ether_addr *dmac, uint32_t sip, uint32_t dip,
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
uint8_t flags, uint8_t *payload, uint16_t payload_len);
static int send_tcp_packet(uint32_t dip, uint16_t dport, uint16_t sport, uint32_t seq,
uint32_t ack, uint8_t flags, uint8_t *payload, uint16_t payload_len);
static int tcp_connect(uint32_t dip, uint16_t dport, uint16_t sport);
static int tcp_send_data(uint32_t dip, uint16_t dport, uint16_t sport, uint8_t *data, uint16_t len);
static int tcp_close(uint32_t dip, uint16_t dport, uint16_t sport);
static void handle_tcp_packet(__attribute__((unused))struct rte_ether_hdr *ethhdr, struct rte_ipv4_hdr *iphdr, struct rte_tcp_hdr *tcphdr);
static int tcp_table_add(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port, tcp_state_t state);
static int tcp_table_update_state(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port, tcp_state_t new_state);
static tcp_conn_entry_t* tcp_table_lookup(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port);
static void tcp_table_print(void);
static uint32_t generate_seq_num(void);
void *cli_thread_func(__attribute__((unused)) void *arg);
// 端口配置,仅仅指定接收数据包的最大长度为以太网的最大帧长
static const struct rte_eth_conf port_conf_default = {
.rxmode = {.max_rx_pkt_len = RTE_ETHER_MAX_LEN}
};
// ====================== ARP表相关函数 ======================
static void arp_table_init(void){
memset(&g_arp_table,0,sizeof(arp_table_t));
pthread_mutex_init(&g_arp_table.mutex,NULL);
// 初始化所有条目为无效
for(int i = 0;i < ARP_TABLE_MAX_ENTRY;i++){
g_arp_table.entries[i].valid = 0;
g_arp_table.entries[i].ip_addr = 0;
memset(&g_arp_table.entries[i].mac,0,sizeof(struct rte_ether_addr));
g_arp_table.entries[i].update_time = 0;
}
}
static int arp_table_lookup(u32 ip_addr,struct rte_ether_addr *mac){
pthread_mutex_lock(&g_arp_table.mutex);
for(int i = 0;i < ARP_TABLE_MAX_ENTRY;i++){
if(g_arp_table.entries[i].valid && g_arp_table.entries[i].ip_addr == ip_addr){
// 检查是否过期
time_t now = time(NULL);
if(now - g_arp_table.entries[i].update_time > ARP_ENTRY_EXPIRE_SEC){
printf("⚠️ ARP条目[%s]已过期,自动删除 ⚠️\n",
inet_ntoa(*(struct in_addr*)&ip_addr));
g_arp_table.entries[i].valid = 0;
pthread_mutex_unlock(&g_arp_table.mutex);
return -1;
}
// 找到有效条目
memcpy(mac, &g_arp_table.entries[i].mac, sizeof(struct rte_ether_addr));
pthread_mutex_unlock(&g_arp_table.mutex);
return 0;
}
}
pthread_mutex_unlock(&g_arp_table.mutex);
return -1; // 未找到
}
static int arp_table_update(u32 ip_addr,struct rte_ether_addr *mac){
pthread_mutex_lock(&g_arp_table.mutex);
// 先查找是否已有该IP
for(int i = 0;i < ARP_TABLE_MAX_ENTRY;i++){
if(g_arp_table.entries[i].ip_addr == ip_addr){
// 更新现有条目
memcpy(&g_arp_table.entries[i].mac, mac, sizeof(struct rte_ether_addr));
g_arp_table.entries[i].update_time = time(NULL);
g_arp_table.entries[i].valid = 1;
pthread_mutex_unlock(&g_arp_table.mutex);
return 0;
}
}
// 查找空条目
for(int i = 0;i < ARP_TABLE_MAX_ENTRY;i++){
if(!g_arp_table.entries[i].valid){
g_arp_table.entries[i].ip_addr = ip_addr;
memcpy(&g_arp_table.entries[i].mac, mac, sizeof(struct rte_ether_addr));
g_arp_table.entries[i].update_time = time(NULL);
g_arp_table.entries[i].valid = 1;
pthread_mutex_unlock(&g_arp_table.mutex);
return 0;
}
}
// 表满,替换最旧的条目
int oldest_idx = 0;
time_t oldest_time = g_arp_table.entries[0].update_time;
for (int i = 1; i < ARP_TABLE_MAX_ENTRY; i++) {
if (g_arp_table.entries[i].update_time < oldest_time) {
oldest_time = g_arp_table.entries[i].update_time;
oldest_idx = i;
}
}
printf("⚠️ ARP表已满,替换最旧条目[%s] ⚠️\n",
inet_ntoa(*(struct in_addr*)&g_arp_table.entries[oldest_idx].ip_addr));
g_arp_table.entries[oldest_idx].ip_addr = ip_addr;
memcpy(&g_arp_table.entries[oldest_idx].mac, mac, sizeof(struct rte_ether_addr));
g_arp_table.entries[oldest_idx].update_time = time(NULL);
g_arp_table.entries[oldest_idx].valid = 1;
pthread_mutex_unlock(&g_arp_table.mutex);
return 0;
}
static void arp_table_print(void) {
printf("\n=================== ARP 表 ===================\n");
printf("IP地址\t\t\tMAC地址\t\t\t过期时间(秒)\n");
printf("----------------------------------------------\n");
pthread_mutex_lock(&g_arp_table.mutex);
time_t now = time(NULL);
for (int i = 0; i < ARP_TABLE_MAX_ENTRY; i++) {
if (g_arp_table.entries[i].valid) {
struct in_addr ip_addr;
ip_addr.s_addr = g_arp_table.entries[i].ip_addr;
int expire_left = ARP_ENTRY_EXPIRE_SEC - (now - g_arp_table.entries[i].update_time);
if (expire_left < 0) expire_left = 0;
printf("%s\t\t%02x:%02x:%02x:%02x:%02x:%02x\t\t%d\n",
inet_ntoa(ip_addr),
g_arp_table.entries[i].mac.addr_bytes[0],
g_arp_table.entries[i].mac.addr_bytes[1],
g_arp_table.entries[i].mac.addr_bytes[2],
g_arp_table.entries[i].mac.addr_bytes[3],
g_arp_table.entries[i].mac.addr_bytes[4],
g_arp_table.entries[i].mac.addr_bytes[5],
expire_left);
}
}
pthread_mutex_unlock(&g_arp_table.mutex);
printf("==============================================\n\n");
}
static void arp_table_clean_expired(void) {
pthread_mutex_lock(&g_arp_table.mutex);
time_t now = time(NULL);
int cleaned = 0;
for (int i = 0; i < ARP_TABLE_MAX_ENTRY; i++) {
if (g_arp_table.entries[i].valid &&
(now - g_arp_table.entries[i].update_time > ARP_ENTRY_EXPIRE_SEC)) {
g_arp_table.entries[i].valid = 0;
cleaned++;
}
}
pthread_mutex_unlock(&g_arp_table.mutex);
// if (cleaned > 0) {
// printf("🧹 清理了%d个过期ARP条目 🧹\n", cleaned);
// } else {
// printf("✅ 无过期ARP条目需要清理 ✅\n");
// }
}
// ====================== ICMP相关函数 ======================
// 计算ICMP校验和
static uint16_t icmp_checksum(const void *data, uint16_t len) {
const uint16_t *buf = (const uint16_t *)data;
uint32_t sum = 0;
uint16_t result;
while (len > 1) {
sum += *buf++;
len -= 2;
}
if (len == 1) {
sum += *(const uint8_t *)buf;
}
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
result = ~sum;
return result;
}
//编码icmp请求
static int encode_icmp_echo_request(u8 *msg,u32 dip,u16 seq){
//1. 以太网头
struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
struct rte_ether_addr dmac;
if (arp_table_lookup(dip, &dmac) < 0) {
printf("❌ 未找到目标IP[%s]的MAC地址 ❌\n", inet_ntoa(*(struct in_addr*)&dip));
return -1;
}
memcpy(eth->d_addr.addr_bytes, dmac.addr_bytes, RTE_ETHER_ADDR_LEN);
memcpy(eth->s_addr.addr_bytes, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
//2. IP头
struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(eth + 1);
ip->version_ihl = 0x45; // IPv4,头长20字节
ip->type_of_service = 0;
uint16_t ip_total_len = sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr) + ICMP_ECHO_DATA_LEN;
ip->total_length = htons(ip_total_len);
ip->packet_id = 0;
ip->fragment_offset = 0;
ip->time_to_live = 64;
ip->next_proto_id = IPPROTO_ICMP;
ip->src_addr = gPortIpAddr;
ip->dst_addr = dip;
ip->hdr_checksum = 0;
ip->hdr_checksum = rte_ipv4_cksum(ip);
//3. ICMP头
struct rte_icmp_hdr *icmp = (struct rte_icmp_hdr *)(ip + 1);
icmp->icmp_type = RTE_IP_ICMP_ECHO_REQUEST; //回显请求
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_ident = htons(ICMP_ID); //区分一台主机上不同进程发起的ping请求
icmp->icmp_seq_nb = htons(seq); //ping包的序号
// 4. ICMP数据(填充随机数据,标准Ping包56字节)
uint8_t *icmp_data = (uint8_t *)(icmp + 1);
for (int i = 0; i < ICMP_ECHO_DATA_LEN; i++) {
icmp_data[i] = i % 0xFF; // 填充简单数据
}
// 5. 计算ICMP校验和
icmp->icmp_cksum = icmp_checksum(icmp, sizeof(struct rte_icmp_hdr) + ICMP_ECHO_DATA_LEN);
return 0;
}
//编码icmp应答包
// 输出:存放组装好的ICMP响应包的内存起始地址
// 输入:原始Ping请求包的以太网头
// 输入:原始Ping请求包的IP头
// 输入:原始Ping请求包的ICMP头
static int encode_icmp_echo_reply(u8 *msg, struct rte_ether_hdr *orig_eth,
struct rte_ipv4_hdr *orig_ip, struct rte_icmp_hdr *orig_icmp) {
// 1. 以太网头(源MAC和目标MAC互换)
struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
memcpy(eth->d_addr.addr_bytes, orig_eth->s_addr.addr_bytes, RTE_ETHER_ADDR_LEN);
memcpy(eth->s_addr.addr_bytes, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
// 2. IP头(源IP和目标IP互换)
struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(eth + 1);
ip->version_ihl = 0x45;
ip->type_of_service = 0;
ip->total_length = orig_ip->total_length; // 长度不变
ip->packet_id = 0;
ip->fragment_offset = 0;
ip->time_to_live = 64;
ip->next_proto_id = IPPROTO_ICMP;
ip->src_addr = gPortIpAddr;
ip->dst_addr = orig_ip->src_addr;
ip->hdr_checksum = 0;
ip->hdr_checksum = rte_ipv4_cksum(ip);
// 3. ICMP头(类型改为响应,复用原ID和序列号)
struct rte_icmp_hdr *icmp = (struct rte_icmp_hdr *)(ip + 1);
icmp->icmp_type = RTE_IP_ICMP_ECHO_REPLY; // 回显响应
icmp->icmp_code = 0;
icmp->icmp_cksum = 0;
icmp->icmp_ident = orig_icmp->icmp_ident;
icmp->icmp_seq_nb = orig_icmp->icmp_seq_nb;
// 4. 复用原ICMP数据
uint16_t icmp_data_len = ntohs(orig_ip->total_length) - sizeof(struct rte_ipv4_hdr) - sizeof(struct rte_icmp_hdr);
uint8_t *orig_data = (uint8_t *)(orig_icmp + 1);
uint8_t *reply_data = (uint8_t *)(icmp + 1);
memcpy(reply_data, orig_data, icmp_data_len);
// 5. 重新计算ICMP校验和
icmp->icmp_cksum = icmp_checksum(icmp, sizeof(struct rte_icmp_hdr) + icmp_data_len);
return 0;
}
//发送icmp请求包
static int send_icmp_echo_request(u32 dip,u16 seq){
uint16_t total_len = sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_icmp_hdr) +
ICMP_ECHO_DATA_LEN;
// 分配MBUF
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(g_mbuf_pool);
if (!mbuf) {
printf("❌ 分配ICMP MBUF失败 ❌\n");
return -1;
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
// 编码ICMP请求包
u8 *msg = rte_pktmbuf_mtod(mbuf, u8 *);
if (encode_icmp_echo_request(msg, dip, seq) < 0) {
rte_pktmbuf_free(mbuf);
return -1;
}
// 发送ICMP包
int ret = rte_eth_tx_burst(global_portid, 0, &mbuf, 1);
if (ret != 1) {
printf("❌ ICMP请求发送失败 ❌\n");
rte_pktmbuf_free(mbuf);
return -1;
}
//记录发送时间
pthread_mutex_lock(&g_ping_mutex);
gettimeofday(&g_ping_ctx.send_time,NULL);
g_ping_ctx.seq = seq;
g_ping_ctx.target_ip = dip;
g_ping_ctx.recv_flag = 0;
pthread_mutex_unlock(&g_ping_mutex);
struct in_addr ip_addr;
ip_addr.s_addr = dip;
printf("📤 发送ICMP请求到 %s (seq=%d) 📤\n", inet_ntoa(ip_addr), seq);
return 0;
}
static void handle_icmp_echo_request(struct rte_ether_hdr *ethhdr, struct rte_ipv4_hdr *iphdr, struct rte_icmp_hdr *icmphdr) {
// 只处理目标IP为本机的回显请求
if (iphdr->dst_addr != gPortIpAddr || icmphdr->icmp_type != RTE_IP_ICMP_ECHO_REQUEST) {
return;
}
// 计算数据包总长度
uint16_t icmp_data_len = ntohs(iphdr->total_length) - sizeof(struct rte_ipv4_hdr) - sizeof(struct rte_icmp_hdr);
uint16_t total_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_icmp_hdr) + icmp_data_len;
// 分配MBUF
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(g_mbuf_pool);
if (!mbuf) {
printf("❌ 分配ICMP响应MBUF失败 ❌\n");
return;
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
// 编码ICMP响应包
u8 *msg = rte_pktmbuf_mtod(mbuf, u8 *);
encode_icmp_echo_reply(msg, ethhdr, iphdr, icmphdr);
// 发送响应包
int ret = rte_eth_tx_burst(global_portid, 0, &mbuf, 1);
if (ret != 1) {
printf("❌ ICMP响应发送失败 ❌\n");
rte_pktmbuf_free(mbuf);
return;
}
struct in_addr ip_addr;
ip_addr.s_addr = iphdr->src_addr;
printf("📥 收到ICMP请求,已响应 %s (seq=%d) 📥\n",
inet_ntoa(ip_addr), ntohs(icmphdr->icmp_seq_nb));
}
static void handle_icmp_echo_reply(struct rte_icmp_hdr *icmphdr,struct rte_ipv4_hdr *iphdr){
pthread_mutex_lock(&g_ping_mutex);
// 匹配目标IP、ID、序列号
if (g_ping_ctx.target_ip != iphdr->src_addr ||
ntohs(icmphdr->icmp_ident) != ICMP_ID ||
ntohs(icmphdr->icmp_seq_nb) != g_ping_ctx.seq) {
pthread_mutex_unlock(&g_ping_mutex);
return;
}
// 计算往返时间(RTT)
struct timeval recv_time;
gettimeofday(&recv_time, NULL);
double sec = recv_time.tv_sec - g_ping_ctx.send_time.tv_sec;
double usec = recv_time.tv_usec - g_ping_ctx.send_time.tv_usec;
g_ping_ctx.rtt = (sec * 1000) + (usec / 1000);
g_ping_ctx.recv_flag = 1;
struct in_addr ip_addr;
ip_addr.s_addr = iphdr->src_addr;
printf("📥 收到ICMP响应 from %s (seq=%d) 耗时=%.2f ms 📥\n",
inet_ntoa(ip_addr), g_ping_ctx.seq, g_ping_ctx.rtt);
pthread_mutex_unlock(&g_ping_mutex);
}
static int ping_target(u32 target_ip) {
// 先发送ARP请求获取MAC
for (int i = 0; i < ARP_REQUEST_RETRY; i++) {
send_arp_request(target_ip);
sleep(ARP_REQUEST_INTERVAL);
struct rte_ether_addr mac;
if (arp_table_lookup(target_ip, &mac) == 0) {
break;
}
}
// 初始化Ping上下文
pthread_mutex_lock(&g_ping_mutex);
g_ping_ctx.target_ip = target_ip;
g_ping_ctx.recv_flag = 0;
g_ping_ctx.rtt = 0;
pthread_mutex_unlock(&g_ping_mutex);
int success = 0;
struct in_addr ip_addr;
ip_addr.s_addr = target_ip;
printf("\n🏓 PING %s (%s) 56(84) bytes of data. 🏓\n",
inet_ntoa(ip_addr), inet_ntoa(ip_addr));
// 发送多个Ping请求
for (int i = 0; i < ICMP_REQUEST_RETRY; i++) {
send_icmp_echo_request(target_ip, i + 1);
// 等待响应
sleep(ICMP_REQUEST_TIMEOUT);
pthread_mutex_lock(&g_ping_mutex);
if (g_ping_ctx.recv_flag) {
success++;
} else {
printf("⌛ ICMP请求超时 (seq=%d) ⌛\n", i + 1);
}
pthread_mutex_unlock(&g_ping_mutex);
}
// 打印Ping统计
printf("\n--- %s ping 统计 ---\n", inet_ntoa(ip_addr));
printf("%d 个包已发送, %d 个包已接收, %d%% 丢包率\n",
ICMP_REQUEST_RETRY, success, (ICMP_REQUEST_RETRY - success) * 100 / ICMP_REQUEST_RETRY);
return success > 0 ? 0 : -1;
}
// 处理接收到的UDP包
static void handle_udp_packet(__attribute__((unused))struct rte_ether_hdr *ethhdr, struct rte_ipv4_hdr *iphdr, struct rte_udp_hdr *udphdr) {
// 只处理目标IP为本机的UDP包
if (iphdr->dst_addr != gPortIpAddr) {
return;
}
// 计算UDP负载长度
uint16_t udp_total_len = ntohs(udphdr->dgram_len);
uint16_t payload_len = udp_total_len - sizeof(struct rte_udp_hdr);
uint8_t *payload = (uint8_t*)(udphdr + 1);
// 打印UDP接收信息
struct in_addr src_ip, dst_ip;
src_ip.s_addr = iphdr->src_addr;
dst_ip.s_addr = iphdr->dst_addr;
printf("📥 收到UDP包 📥\n");
printf(" 源:%s:%d\n", inet_ntoa(src_ip), ntohs(udphdr->src_port));
printf(" 目标:%s:%d\n", inet_ntoa(dst_ip), ntohs(udphdr->dst_port));
printf(" 负载长度:%d字节\n", payload_len);
printf(" 负载内容:%.*s\n", payload_len, payload);
}
// ====================== 端口初始化与ARP发送函数 ======================
static int ustack_init_port(struct rte_mempool *mbuf_pool){
u16 nb_sys_ports = rte_eth_dev_count_avail();
if (nb_sys_ports == 0) {
rte_exit(EXIT_FAILURE, "No Supported eth found\n");
}
struct rte_eth_dev_info dev_info;
rte_eth_dev_info_get(global_portid,&dev_info);
const int num_rx_queues = 1;
const int num_tx_queues = 1;
// 配置以太网端口
if (rte_eth_dev_configure(global_portid, num_rx_queues, num_tx_queues, &port_conf_default) < 0) {
rte_exit(EXIT_FAILURE, "Could not configure eth dev\n");
}
// 配置rx队列
if (rte_eth_rx_queue_setup(global_portid, 0, 128, rte_eth_dev_socket_id(global_portid), NULL, mbuf_pool) < 0) {
rte_exit(EXIT_FAILURE, "Could not setup RX queue\n");
}
// 配置tx队列
struct rte_eth_txconf txq_conf = dev_info.default_txconf;
txq_conf.offloads = port_conf_default.rxmode.offloads;
if (rte_eth_tx_queue_setup(global_portid, 0, 512, rte_eth_dev_socket_id(global_portid), &txq_conf) < 0) {
rte_exit(EXIT_FAILURE, "Could not setup TX queue\n");
}
if(rte_eth_dev_start(global_portid) < 0){
rte_exit(EXIT_FAILURE, "Could not start eth dev\n");
}
// 获取本机MAC和IP
rte_eth_macaddr_get(global_portid, &gPortMacAddr);
gPortIpAddr = inet_addr("192.168.3.100"); // 可根据实际情况修改
// 启用混杂模式
rte_eth_promiscuous_enable(global_portid);
printf("✅ 端口初始化完成 ✅\n");
printf(" 本机MAC:%02x:%02x:%02x:%02x:%02x:%02x\n",
gPortMacAddr.addr_bytes[0], gPortMacAddr.addr_bytes[1],
gPortMacAddr.addr_bytes[2], gPortMacAddr.addr_bytes[3],
gPortMacAddr.addr_bytes[4], gPortMacAddr.addr_bytes[5]);
printf(" 本机IP:%s\n", inet_ntoa(*(struct in_addr*)&gPortIpAddr));
return 0;
}
static int ustack_encode_arp_request(u8 *msg,u32 target_ip){
// 以太网头
struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
// 广播MAC
memset(eth->d_addr.addr_bytes, 0xff, RTE_ETHER_ADDR_LEN);
memcpy(eth->s_addr.addr_bytes, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_ARP);
// ARP头
struct rte_arp_hdr *arp = (struct rte_arp_hdr *)(eth + 1);
arp->arp_hardware = htons(RTE_ARP_HRD_ETHER); // 以太网
arp->arp_protocol = htons(RTE_ETHER_TYPE_IPV4);
arp->arp_hlen = RTE_ETHER_ADDR_LEN;
arp->arp_plen = sizeof(uint32_t);
arp->arp_opcode = htons(RTE_ARP_OP_REQUEST);
// ARP发送方(本机)
memcpy(&arp->arp_data.arp_sha, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
arp->arp_data.arp_sip = gPortIpAddr;
// ARP目标方
memset(&arp->arp_data.arp_tha, 0, RTE_ETHER_ADDR_LEN); // 目标MAC未知
arp->arp_data.arp_tip = target_ip;
return 0;
}
static int send_arp_request(u32 target_ip){
u16 total_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_arp_hdr);
// 分配MBUF
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(g_mbuf_pool);
if (!mbuf) {
printf("❌ 分配ARP MBUF失败 ❌\n");
return -1;
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
// 填充arp请求包
u8 *msg = rte_pktmbuf_mtod(mbuf,u8 *);
ustack_encode_arp_request(msg, target_ip);
// 发送arp请求
int ret = rte_eth_tx_burst(global_portid,0,&mbuf,1);
if (ret != 1) {
printf("❌ ARP请求发送失败 ❌\n");
rte_pktmbuf_free(mbuf);
return -1;
}
struct in_addr ip_addr;
ip_addr.s_addr = target_ip;
printf("📤 发送ARP请求到 %s 📤\n", inet_ntoa(ip_addr));
return 0;
}
static void handle_arp_response(struct rte_arp_hdr *ahdr, __attribute__((unused)) struct rte_ether_hdr *ethhdr) {
// 只处理目标IP为本机的ARP响应
if (ahdr->arp_data.arp_tip != gPortIpAddr) {
return;
}
// 更新ARP表
struct rte_ether_addr mac;
memcpy(&mac, &ahdr->arp_data.arp_sha, RTE_ETHER_ADDR_LEN);
arp_table_update(ahdr->arp_data.arp_sip, &mac);
// 打印ARP响应信息
struct in_addr ip_addr;
ip_addr.s_addr = ahdr->arp_data.arp_sip;
printf("📥 收到ARP响应 📥\n");
printf(" IP:%s -> MAC:%02x:%02x:%02x:%02x:%02x:%02x\n",
inet_ntoa(ip_addr),
mac.addr_bytes[0], mac.addr_bytes[1],
mac.addr_bytes[2], mac.addr_bytes[3],
mac.addr_bytes[4], mac.addr_bytes[5]);
}
// ====================== UDP相关函数 ======================
static int ustack_encode_udp_pkt(uint8_t *msg, struct rte_ether_addr *dmac,
uint32_t sip, uint32_t dip, uint16_t sport,
uint16_t dport, uint8_t *payload, uint16_t payload_len) {
// 1. 以太网头
struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
memcpy(eth->d_addr.addr_bytes, dmac->addr_bytes, RTE_ETHER_ADDR_LEN);
memcpy(eth->s_addr.addr_bytes, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
// 2. IP头
struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(eth + 1);
ip->version_ihl = 0x45; // IPv4, 头长20字节
ip->type_of_service = 0;
uint16_t ip_total_len = sizeof(struct rte_ipv4_hdr) + sizeof(struct rte_udp_hdr) + payload_len;
ip->total_length = htons(ip_total_len);
ip->packet_id = 0;
ip->fragment_offset = 0;
ip->time_to_live = 64;
ip->next_proto_id = IPPROTO_UDP;
ip->src_addr = sip;
ip->dst_addr = dip;
ip->hdr_checksum = 0;
ip->hdr_checksum = rte_ipv4_cksum(ip);
// 3. UDP头
struct rte_udp_hdr *udp = (struct rte_udp_hdr *)(ip + 1);
udp->src_port = htons(sport);
udp->dst_port = htons(dport);
uint16_t udp_len = sizeof(struct rte_udp_hdr) + payload_len;
udp->dgram_len = htons(udp_len);
// 4. 拷贝负载
memcpy((uint8_t*)(udp + 1), payload, payload_len);
udp->dgram_cksum = 0;
udp->dgram_cksum = rte_ipv4_udptcp_cksum(ip, udp);
return 0;
}
static int send_udp_packet(uint32_t dip, uint16_t dport, uint16_t sport, uint8_t *payload, uint16_t payload_len) {
// 1. 查找ARP表获取目标MAC
struct rte_ether_addr dmac;
if (arp_table_lookup(dip, &dmac) < 0) {
printf("❌ ARP表中未找到%s的MAC地址,请先发送ARP请求 ❌\n", inet_ntoa(*(struct in_addr*)&dip));
return -1;
}
// 2. 计算总长度
uint16_t total_len = sizeof(struct rte_ether_hdr) +
sizeof(struct rte_ipv4_hdr) +
sizeof(struct rte_udp_hdr) +
payload_len;
// 3. 分配MBUF
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(g_mbuf_pool);
if (!mbuf) {
printf("❌ 分配UDP MBUF失败 ❌\n");
return -1;
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
// 4. 编码UDP包
uint8_t *msg = rte_pktmbuf_mtod(mbuf, uint8_t *);
ustack_encode_udp_pkt(msg, &dmac, gPortIpAddr, dip, sport, dport, payload, payload_len);
// 5. 发送UDP包
int ret = rte_eth_tx_burst(global_portid, 0, &mbuf, 1);
if (ret != 1) {
printf("❌ UDP包发送失败 ❌\n");
rte_pktmbuf_free(mbuf);
return -1;
}
// 打印发送信息
struct in_addr dst_ip;
dst_ip.s_addr = dip;
printf("✅ UDP包发送成功 ✅\n");
printf(" 目标:%s:%d\n", inet_ntoa(dst_ip), dport);
printf(" 源端口:%d\n", sport);
printf(" 负载长度:%d字节\n", payload_len);
printf(" 负载内容:%.*s\n", payload_len, payload);
return 0;
}
// ====================== TCP相关函数实现 ======================
static void tcp_table_init(void){
memset(&g_tcp_table,0,sizeof(tcp_table_t));
pthread_mutex_init(&g_tcp_table.mutex,NULL);
for(int i = 0;i < TCP_TABLE_MAX_ENTRY;i++){
g_tcp_table.entries[i].valid = 0;
g_tcp_table.entries[i].state = TCP_STATE_CLOSED;
// 新增:初始化接收缓冲区
memset(g_tcp_table.entries[i].recv_buf, 0, sizeof(g_tcp_table.entries[i].recv_buf));
g_tcp_table.entries[i].recv_buf_len = 0;
g_tcp_table.entries[i].recv_next_seq = 0;
}
}
// 清理无效TCP连接(新增TIME_WAIT/SYN_RECV清理)
static void tcp_table_clean_invalid(void) {
pthread_mutex_lock(&g_tcp_table.mutex);
time_t now = time(NULL);
int cleaned = 0;
for (int i = 0; i < TCP_TABLE_SIZE; i++) {
tcp_conn_entry_t *entry = &g_tcp_table.entries[i];
if (!entry->valid) continue;
// 清理CLOSED状态(超过清理间隔)
if (entry->state == TCP_STATE_CLOSED && (now - entry->last_active) > TCP_CLOSED_CLEAN_INTERVAL) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
}
// 清理TIME_WAIT状态(标准60秒超时)
else if (entry->state == TCP_STATE_TIME_WAIT && (now - entry->last_active) > TCP_TIME_WAIT_TIMEOUT) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
}
// 清理SYN_RECV半连接(超时10秒未完成三次握手)
else if (entry->state == TCP_STATE_SYN_RECV && (now - entry->last_active) > TCP_SYN_RECV_TIMEOUT) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
if (cleaned > 0) {
printf("🧹 清理了%d个无效TCP连接(TIME_WAIT/SYN_RECV/CLOSED)🧹\n", cleaned);
}
}
// 重置指定的TCP连接条目(彻底清空)
static int tcp_table_reset_entry(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) {
pthread_mutex_lock(&g_tcp_table.mutex);
for (int i = 0; i < TCP_TABLE_MAX_ENTRY; i++) {
if (g_tcp_table.entries[i].valid &&
g_tcp_table.entries[i].src_ip == src_ip &&
g_tcp_table.entries[i].dst_ip == dst_ip &&
g_tcp_table.entries[i].src_port == src_port &&
g_tcp_table.entries[i].dst_port == dst_port) {
memset(&g_tcp_table.entries[i], 0, sizeof(tcp_conn_entry_t));
pthread_mutex_unlock(&g_tcp_table.mutex);
return 0;
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
return -1;
}
//生成随机序列号
static u32 generate_seq_num(void){
static int init = 0; //标记随机数种子是否被初始化
if(!init){
srand(time(NULL));
init = 1;
}
return (u32)rand() | ((u32)rand() << 16);
}
// TCP校验和计算函数
// 参数:ip=IPv4头部指针,tcp=TCP头部指针,tcp_len=TCP报文总长度(头部+数据)
// 返回值:16位的TCP校验和
static uint16_t tcp_checksum(struct rte_ipv4_hdr *ip, struct rte_tcp_hdr *tcp, uint16_t tcp_len) {
uint32_t sum = 0;
// 伪头部(严格按网络字节序填充)
uint8_t pseudo_header[12];
memset(pseudo_header, 0, 12);
// 源IP(4字节,网络序)
memcpy(&pseudo_header[0], &ip->src_addr, 4);
// 目的IP(4字节,网络序)
memcpy(&pseudo_header[4], &ip->dst_addr, 4);
// 保留位(1字节)+ 协议号(1字节)
pseudo_header[8] = 0;
pseudo_header[9] = IPPROTO_TCP; // TCP协议号固定为6
// TCP长度(2字节,网络序)
uint16_t tcp_len_n = htons(tcp_len);
memcpy(&pseudo_header[10], &tcp_len_n, 2);
// 计算伪头部校验和
uint16_t *phdr = (uint16_t *)pseudo_header;
for (int i = 0; i < 6; i++) {
sum += phdr[i];
}
// 计算TCP头部+数据校验和
uint16_t *tcp_data = (uint16_t *)tcp;
int len = tcp_len;
while (len > 1) {
sum += *tcp_data++;
len -= 2;
}
if (len == 1) {
sum += *(uint8_t *)tcp_data;
}
// 折叠校验和
sum = (sum >> 16) + (sum & 0xFFFF);
sum += (sum >> 16);
return (uint16_t)(~sum);
}
// 编码TCP数据包
// 编码TCP数据包
static int encode_tcp_packet(uint8_t *msg, struct rte_ether_addr *dmac, uint32_t sip, uint32_t dip,
uint16_t sport, uint16_t dport, uint32_t seq, uint32_t ack,
uint8_t flags, uint8_t *payload, uint16_t payload_len) {
// 1. 以太网头
struct rte_ether_hdr *eth = (struct rte_ether_hdr *)msg;
memcpy(eth->d_addr.addr_bytes, dmac->addr_bytes, RTE_ETHER_ADDR_LEN);
memcpy(eth->s_addr.addr_bytes, gPortMacAddr.addr_bytes, RTE_ETHER_ADDR_LEN);
eth->ether_type = htons(RTE_ETHER_TYPE_IPV4);
// 2. IP头
struct rte_ipv4_hdr *ip = (struct rte_ipv4_hdr *)(eth + 1);
uint16_t tcp_hdr_len = sizeof(struct rte_tcp_hdr); // TCP头部固定20字节
uint16_t tcp_len = tcp_hdr_len + payload_len;
uint16_t ip_total_len = sizeof(struct rte_ipv4_hdr) + tcp_len;
ip->version_ihl = 0x45; // IPv4,头长20字节
ip->type_of_service = 0;
ip->total_length = htons(ip_total_len);
ip->packet_id = 0;
ip->fragment_offset = 0;
ip->time_to_live = TCP_TTL;
ip->next_proto_id = IPPROTO_TCP;
ip->src_addr = sip;
ip->dst_addr = dip;
ip->hdr_checksum = 0;
ip->hdr_checksum = rte_ipv4_cksum(ip);
// 3. tcp头
struct rte_tcp_hdr *tcp = (struct rte_tcp_hdr *)(ip + 1);
tcp->src_port = htons(sport);
tcp->dst_port = htons(dport);
tcp->sent_seq = htonl(seq);
tcp->recv_ack = htonl(ack);
// 修复:TCP头部长度计算(20字节 = 5 * 4,左移4位占高4位)
tcp->data_off = 0x50; // 等价于 (5) << 4,固定20字节头部
tcp->tcp_flags = flags;
tcp->rx_win = htons(TCP_WINDOW_SIZE);
tcp->cksum = 0;
tcp->tcp_urp = 0;
// 4. 拷贝负载数据
if (payload_len > 0 && payload != NULL) {
memcpy((uint8_t *)(tcp + 1), payload, payload_len);
}
// 5. 计算TCP校验和
tcp->cksum = tcp_checksum(ip, tcp, tcp_len);
return 0;
}
//发送tcp数据包
static int send_tcp_packet(uint32_t dip, uint16_t dport, uint16_t sport, uint32_t seq,
uint32_t ack, uint8_t flags, uint8_t *payload, uint16_t payload_len) {
//1. 查找arp表获取目标MAC地址
struct rte_ether_addr dmac;
if(arp_table_lookup(dip,&dmac) < 0){
printf("❌ ARP表中未找到%s的MAC地址 ❌\n", inet_ntoa(*(struct in_addr*)&dip));
return -1;
}
// 2. 计算总长度
uint16_t tcp_len = sizeof(struct rte_tcp_hdr) + payload_len;
uint16_t total_len = sizeof(struct rte_ether_hdr) + sizeof(struct rte_ipv4_hdr) + tcp_len;
// 3. 分配MBUF
struct rte_mbuf *mbuf = rte_pktmbuf_alloc(g_mbuf_pool);
if (!mbuf) {
printf("❌ 分配TCP MBUF失败 ❌\n");
return -1;
}
mbuf->pkt_len = total_len;
mbuf->data_len = total_len;
// 4. 编码TCP包
uint8_t *msg = rte_pktmbuf_mtod(mbuf, uint8_t *);
encode_tcp_packet(msg, &dmac, gPortIpAddr, dip, sport, dport, seq, ack, flags, payload, payload_len);
// 5. 发送TCP包
int ret = rte_eth_tx_burst(global_portid, 0, &mbuf, 1);
if (ret != 1) {
printf("❌ TCP包发送失败 ❌\n");
rte_pktmbuf_free(mbuf);
return -1;
}
// 打印发送信息
struct in_addr dst_ip;
dst_ip.s_addr = dip;
char flag_str[32] = {0};
if (flags & RTE_TCP_SYN_FLAG) strcat(flag_str, "SYN ");
if (flags & RTE_TCP_ACK_FLAG) strcat(flag_str, "ACK ");
if (flags & RTE_TCP_FIN_FLAG) strcat(flag_str, "FIN ");
if (flags & RTE_TCP_RST_FLAG) strcat(flag_str, "RST ");
printf("✅ TCP包发送成功 ✅\n");
printf(" 目标:%s:%d\n", inet_ntoa(dst_ip), dport);
printf(" 源端口:%d\n", sport);
printf(" 标志位:%s\n", flag_str);
printf(" 序列号:%u, 确认号:%u\n", seq, ack);
printf(" 负载长度:%d字节\n", payload_len);
return 0;
}
//添加tcp连接条目
static int tcp_table_add(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port, tcp_state_t state) {
pthread_mutex_lock(&g_tcp_table.mutex);
//查找空条目
for(int i = 0;i < TCP_TABLE_MAX_ENTRY;i++){
if(!g_tcp_table.entries[i].valid){
g_tcp_table.entries[i].src_ip = src_ip;
g_tcp_table.entries[i].dst_ip = dst_ip;
g_tcp_table.entries[i].src_port = src_port;
g_tcp_table.entries[i].dst_port = dst_port;
g_tcp_table.entries[i].valid = 1;
g_tcp_table.entries[i].state = state;
g_tcp_table.entries[i].seq = generate_seq_num();
g_tcp_table.entries[i].ack = 0;
g_tcp_table.entries[i].last_active = time(NULL);
pthread_mutex_unlock(&g_tcp_table.mutex);
return 0;
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("❌ TCP连接表已满 ❌\n");
return -1;
}
// 更新TCP连接状态
static int tcp_table_update_state(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port, tcp_state_t new_state) {
pthread_mutex_lock(&g_tcp_table.mutex);
for (int i = 0; i < TCP_TABLE_MAX_ENTRY; i++) {
if (g_tcp_table.entries[i].valid &&
g_tcp_table.entries[i].src_ip == src_ip &&
g_tcp_table.entries[i].dst_ip == dst_ip &&
g_tcp_table.entries[i].src_port == src_port &&
g_tcp_table.entries[i].dst_port == dst_port) {
g_tcp_table.entries[i].state = new_state;
g_tcp_table.entries[i].last_active = time(NULL);
pthread_mutex_unlock(&g_tcp_table.mutex);
return 0;
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
return -1;
}
// 查找TCP连接(修改:忽略CLOSED状态)
static tcp_conn_entry_t* tcp_table_lookup(uint32_t src_ip, uint32_t dst_ip, uint16_t src_port, uint16_t dst_port) {
pthread_mutex_lock(&g_tcp_table.mutex);
for (int i = 0; i < TCP_TABLE_MAX_ENTRY; i++) {
// 关键修改:增加状态判断,忽略CLOSED状态
if (g_tcp_table.entries[i].valid &&
g_tcp_table.entries[i].state != TCP_STATE_CLOSED &&
g_tcp_table.entries[i].src_ip == src_ip &&
g_tcp_table.entries[i].dst_ip == dst_ip &&
g_tcp_table.entries[i].src_port == src_port &&
g_tcp_table.entries[i].dst_port == dst_port) {
pthread_mutex_unlock(&g_tcp_table.mutex);
return &g_tcp_table.entries[i];
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
return NULL;
}
// 打印TCP连接表
static void tcp_table_print(void) {
printf("\n=================== TCP 连接表 ===================\n");
printf("源IP\t\t源端口\t目标IP\t\t目标端口\t状态\n");
printf("--------------------------------------------------\n");
pthread_mutex_lock(&g_tcp_table.mutex);
//time_t now = time(NULL);
for (int i = 0; i < TCP_TABLE_MAX_ENTRY; i++) {
if (g_tcp_table.entries[i].valid) {
// struct in_addr src_ip, dst_ip;
// src_ip.s_addr = g_tcp_table.entries[i].src_ip;
// dst_ip.s_addr = g_tcp_table.entries[i].dst_ip;
const char *state_str = "";
switch (g_tcp_table.entries[i].state) {
case TCP_STATE_CLOSED: state_str = "CLOSED"; break;
case TCP_STATE_SYN_SENT: state_str = "SYN_SENT"; break;
case TCP_STATE_ESTABLISHED: state_str = "ESTABLISHED"; break;
case TCP_STATE_FIN_WAIT1: state_str = "FIN_WAIT1"; break;
case TCP_STATE_FIN_WAIT2: state_str = "FIN_WAIT2"; break;
case TCP_STATE_CLOSING: state_str = "CLOSING"; break;
case TCP_STATE_TIME_WAIT: state_str = "TIME_WAIT"; break;
case TCP_STATE_LISTEN: state_str = "LISTEN"; break;
case TCP_STATE_SYN_RECV: state_str = "SYN_RECV"; break;
default: state_str = "UNKNOWN";
}
// 优化tcp_table_print的IP打印
char src_ip_str[16] = {0};
char dst_ip_str[16] = {0};
inet_ntop(AF_INET, &g_tcp_table.entries[i].src_ip, src_ip_str, sizeof(src_ip_str));
inet_ntop(AF_INET, &g_tcp_table.entries[i].dst_ip, dst_ip_str, sizeof(dst_ip_str));
printf("%s\t%d\t%s\t%d\t\t%s\n",
src_ip_str, g_tcp_table.entries[i].src_port,
dst_ip_str, g_tcp_table.entries[i].dst_port,
state_str);
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("==================================================\n\n");
}
//主动建立TCP连接(三次握手)(修改重试逻辑)
static int tcp_connect(uint32_t dip,uint16_t dport,uint16_t sport){
// 新增:先清理该端口的旧连接条目
tcp_table_reset_entry(gPortIpAddr, dip, sport, dport);
//1. 先发送ARP请求获取MAC
for(int i = 0;i <ARP_REQUEST_RETRY;i++){
send_arp_request(dip);
sleep(ARP_REQUEST_INTERVAL);
struct rte_ether_addr mac;
if(arp_table_lookup(dip,&mac) == 0){
break;
}
}
//2. 添加连接条目
if(tcp_table_add(gPortIpAddr, dip, sport, dport, TCP_STATE_SYN_SENT) < 0){
return -1;
}
tcp_conn_entry_t *conn = tcp_table_lookup(gPortIpAddr, dip, sport, dport);
if (!conn) {
printf("❌ 无法找到新建的TCP连接条目 ❌\n");
return -1;
}
struct in_addr dst_ip;
dst_ip.s_addr = dip;
printf("\n🔌 正在连接 %s:%d 🔌\n", inet_ntoa(dst_ip), dport);
//3. 发送SYN包(第一次握手)(修改:重试时生成新序列号)
int retry = 0;
while(retry < TCP_SYN_RETRY && g_running){
// 关键修改:每次重试生成新序列号
if (retry > 0) {
pthread_mutex_lock(&g_tcp_table.mutex);
conn->seq = generate_seq_num();
pthread_mutex_unlock(&g_tcp_table.mutex);
}
send_tcp_packet(dip, dport, sport, conn->seq, 0, RTE_TCP_SYN_FLAG, NULL, 0);
// 等待SYN+ACK响应
for(int i=0; i<TCP_SYN_TIMEOUT*10; i++){
usleep(100000);
conn = tcp_table_lookup(gPortIpAddr, dip, sport, dport);
if (conn && conn->state == TCP_STATE_ESTABLISHED) {
printf("✅ TCP连接建立成功 ✅\n");
return 0;
}
}
retry++;
printf("⌛ SYN重试 %d/%d ⌛\n", retry, TCP_SYN_RETRY);
}
printf("❌ TCP连接建立失败 ❌\n");
// 修改:使用reset彻底清空条目,而非仅改状态
tcp_table_reset_entry(gPortIpAddr, dip, sport, dport);
return -1;
}
//发送tcp数据
static int tcp_send_data(uint32_t dip, uint16_t dport, uint16_t sport, uint8_t *data, uint16_t len) {
tcp_conn_entry_t *conn = tcp_table_lookup(gPortIpAddr, dip, sport, dport);
if (!conn || conn->state != TCP_STATE_ESTABLISHED) {
printf("❌ 无有效TCP连接或连接未建立 ❌\n");
return -1;
}
// 关键修复:使用当前最新的seq和ack发送数据
uint32_t current_seq = conn->seq + 1;
uint32_t current_ack = conn->ack;
// 发送数据(带ACK标志)
int ret = send_tcp_packet(dip, dport, sport, current_seq, current_ack,
RTE_TCP_ACK_FLAG, data, len);
if (ret == 0) {
// 更新序列号
pthread_mutex_lock(&g_tcp_table.mutex);
conn->seq = current_seq + len; // 修复:基于发送的seq更新,避免重复
conn->last_active = time(NULL);
pthread_mutex_unlock(&g_tcp_table.mutex);
struct in_addr dst_ip;
dst_ip.s_addr = dip;
printf("📤 发送TCP数据到 %s:%d (长度:%d字节) 📤\n",
inet_ntoa(dst_ip), dport, len);
}
return ret;
}
//关闭tcp连接(四次挥手)(修改:关闭后彻底清理)
static int tcp_close(uint32_t dip,uint16_t dport,uint16_t sport){
tcp_conn_entry_t *conn = tcp_table_lookup(gPortIpAddr, dip, sport, dport);
if (!conn || conn->state == TCP_STATE_CLOSED) {
printf("❌ 无有效TCP连接 ❌\n");
return -1;
}
//1. 发送FIN+ACK包
tcp_table_update_state(gPortIpAddr,dip,sport,dport,TCP_STATE_FIN_WAIT1);
send_tcp_packet(dip,dport,sport,conn->seq + 1,conn->ack,
RTE_TCP_FIN_FLAG | RTE_TCP_ACK_FLAG,NULL,0);
struct in_addr dst_ip;
dst_ip.s_addr = dip;
printf("\n🔚 正在关闭 %s:%d 连接 🔚\n", inet_ntoa(dst_ip), dport);
// 2. 等待响应
int timeout = 0;
while (timeout < TCP_SYN_TIMEOUT * 2 && g_running) {
conn = tcp_table_lookup(gPortIpAddr, dip, sport, dport);
if (!conn || conn->state == TCP_STATE_CLOSED) {
break;
}
sleep(1);
timeout++;
}
// 修改:无论是否超时,都彻底清理条目
tcp_table_reset_entry(gPortIpAddr, dip, sport, dport);
printf("✅ TCP连接已关闭 ✅\n");
return 0;
}
// 处理接收到的TCP数据包
static void handle_tcp_packet(__attribute__((unused))struct rte_ether_hdr *ethhdr, struct rte_ipv4_hdr *iphdr, struct rte_tcp_hdr *tcphdr) {
// 1. 严格过滤:只处理目标IP为本机的TCP包
if (iphdr->dst_addr != gPortIpAddr) {
return;
}
uint32_t src_ip = iphdr->src_addr; // 对方IP
uint32_t dst_ip = iphdr->dst_addr; // 本机IP
uint16_t src_port = ntohs(tcphdr->src_port);
uint16_t dst_port = ntohs(tcphdr->dst_port);
uint32_t seq = ntohl(tcphdr->sent_seq);
uint32_t ack = ntohl(tcphdr->recv_ack);
uint8_t flags = tcphdr->tcp_flags;
// 计算TCP数据长度
uint16_t ip_len = ntohs(iphdr->total_length);
uint16_t tcp_len = ip_len - (iphdr->version_ihl & 0x0F) * 4;
uint16_t data_len = tcp_len - (tcphdr->data_off >> 4) * 4;
uint8_t *data = (uint8_t*)(tcphdr + 1);
// ========== 修复inet_ntoa缓冲区覆盖问题 ==========
char src_ip_str[16] = {0}; // 存储源IP字符串(对方IP)
char dst_ip_str[16] = {0}; // 存储目标IP字符串(本机IP)
inet_ntop(AF_INET, &src_ip, src_ip_str, sizeof(src_ip_str));
inet_ntop(AF_INET, &dst_ip, dst_ip_str, sizeof(dst_ip_str));
// ========== 增强重复包过滤(seq + 数据长度) ==========
typedef struct {
uint32_t src_ip;
uint32_t dst_ip;
uint16_t src_port;
uint16_t dst_port;
uint32_t seq;
uint16_t data_len;
time_t recv_time;
} tcp_packet_cache_t;
static tcp_packet_cache_t packet_cache[32] = {0};
static int cache_idx = 0;
time_t now = time(NULL);
int is_duplicate = 0;
// 检查缓存中是否有相同的包(3秒内)
for (int j = 0; j < 32; j++) {
if (packet_cache[j].src_ip == src_ip &&
packet_cache[j].dst_ip == dst_ip &&
packet_cache[j].src_port == src_port &&
packet_cache[j].dst_port == dst_port &&
packet_cache[j].seq == seq &&
packet_cache[j].data_len == data_len &&
(now - packet_cache[j].recv_time) < 3) {
is_duplicate = 1;
break;
}
}
// 重复包直接忽略
if (is_duplicate) {
printf("⚠️ 检测到重复TCP包,忽略 ⚠️\n");
return;
}
// 更新缓存(FIFO)
packet_cache[cache_idx].src_ip = src_ip;
packet_cache[cache_idx].dst_ip = dst_ip;
packet_cache[cache_idx].src_port = src_port;
packet_cache[cache_idx].dst_port = dst_port;
packet_cache[cache_idx].seq = seq;
packet_cache[cache_idx].data_len = data_len;
packet_cache[cache_idx].recv_time = now;
cache_idx = (cache_idx + 1) % 32;
// 打印TCP包信息
printf("\n📥 收到TCP包 📥\n");
printf(" 源:%s:%d -> 目标:%s:%d\n", src_ip_str, src_port, dst_ip_str, dst_port);
printf(" 标志位:");
if (flags & RTE_TCP_SYN_FLAG) printf("SYN ");
if (flags & RTE_TCP_ACK_FLAG) printf("ACK ");
if (flags & RTE_TCP_FIN_FLAG) printf("FIN ");
if (flags & RTE_TCP_RST_FLAG) printf("RST ");
printf("\n 序列号:%u, 确认号:%u\n", seq, ack);
printf(" 数据长度:%d字节\n", data_len);
if (data_len > 0) {
printf(" 数据内容:%.*s\n", data_len, data);
}
// 2. 查找连接(双向匹配)
tcp_conn_entry_t *active_conn = tcp_table_lookup(gPortIpAddr, src_ip, dst_port, src_port);
tcp_conn_entry_t *passive_conn = tcp_table_lookup(src_ip, gPortIpAddr, src_port, dst_port);
// 3. 处理SYN+ACK包(过滤已建立连接的重复包)
if ((flags & (RTE_TCP_SYN_FLAG | RTE_TCP_ACK_FLAG)) == (RTE_TCP_SYN_FLAG | RTE_TCP_ACK_FLAG)) {
if (active_conn && active_conn->state == TCP_STATE_ESTABLISHED) {
printf("⚠️ 收到已建立连接的重复SYN+ACK包,忽略 ⚠️\n");
return;
}
if (active_conn && active_conn->state == TCP_STATE_SYN_SENT) {
// 更新主动连接状态
tcp_table_update_state(gPortIpAddr, src_ip, dst_port, src_port, TCP_STATE_ESTABLISHED);
// 发送ACK包(第三次握手)
send_tcp_packet(src_ip, src_port, dst_port, ack, seq + 1, RTE_TCP_ACK_FLAG, NULL, 0);
// 核心修复:主动连接 recv_next_seq = seq + 1(对方下一个数据的seq)
pthread_mutex_lock(&g_tcp_table.mutex);
active_conn->ack = seq + 1;
active_conn->recv_next_seq = seq + 1; // 主动连接必须+1
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("📩 收到SYN+ACK包,已回复ACK,连接建立 📩\n");
} else {
printf("⚠️ 收到无效的SYN+ACK包(无对应SYN_SENT连接)⚠️\n");
}
return;
}
// 处理SYN包(被动建立连接:对方发SYN给本机)
else if (flags & RTE_TCP_SYN_FLAG && !(flags & RTE_TCP_ACK_FLAG)) { // 仅纯SYN包
// 被动连接存储:src_ip=对方,dst_ip=本机,src_port=对方端口,dst_port=本机端口
if (tcp_table_add(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_SYN_RECV) == 0) {
uint32_t my_seq = generate_seq_num();
// 回复SYN+ACK:目标=对方IP:对方端口,源=本机IP:本机端口
send_tcp_packet(src_ip, src_port, dst_port, my_seq, seq + 1,
RTE_TCP_SYN_FLAG | RTE_TCP_ACK_FLAG, NULL, 0);
// 记录我方SYN+ACK的seq,用于后续验证
tcp_conn_entry_t *new_conn = tcp_table_lookup(src_ip, gPortIpAddr, src_port, dst_port);
if (new_conn) {
pthread_mutex_lock(&g_tcp_table.mutex);
new_conn->seq = my_seq; // 保存我方发送的seq
new_conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
}
printf("📩 收到SYN包,已回复SYN+ACK 📩\n");
} else {
printf("❌ TCP连接表已满,无法响应SYN包 ❌\n");
}
}
// 处理FIN包(断开连接)
else if (flags & RTE_TCP_FIN_FLAG) {
tcp_conn_entry_t *conn = active_conn ? active_conn : passive_conn;
if (conn) {
// 发送ACK响应
send_tcp_packet(src_ip, src_port, dst_port, ack, seq + 1, RTE_TCP_ACK_FLAG, NULL, 0);
if (conn->state == TCP_STATE_ESTABLISHED) {
// 区分主动/被动连接,更新正确的状态
if (active_conn) {
tcp_table_update_state(gPortIpAddr, src_ip, dst_port, src_port, TCP_STATE_TIME_WAIT);
} else {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_TIME_WAIT);
}
send_tcp_packet(src_ip, src_port, dst_port, conn->seq + 1, seq + 1,
RTE_TCP_FIN_FLAG | RTE_TCP_ACK_FLAG, NULL, 0);
} else {
if (active_conn) {
tcp_table_update_state(gPortIpAddr, src_ip, dst_port, src_port, TCP_STATE_CLOSED);
} else {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_CLOSED);
}
}
// 更新最后活动时间
pthread_mutex_lock(&g_tcp_table.mutex);
conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("📩 收到FIN包,连接进入TIME_WAIT/已关闭 📩\n");
} else {
printf("⚠️ 收到FIN包但无对应连接,忽略 ⚠️\n");
}
}
// 处理ACK包(拆分:1. 完成三次握手 2. 确认关闭)
else if (flags & RTE_TCP_ACK_FLAG && data_len == 0) {
// 场景1:对方回复ACK,完成三次握手(被动连接 → recv_next_seq = seq)
if (passive_conn && passive_conn->state == TCP_STATE_SYN_RECV) {
// 验证ACK号是否正确(应为我方SYN+ACK的seq + 1)
if (ack == (passive_conn->seq + 1)) {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_ESTABLISHED);
// 被动连接 recv_next_seq = seq(对方下一个数据的seq)
pthread_mutex_lock(&g_tcp_table.mutex);
passive_conn->ack = seq + 1;
passive_conn->recv_next_seq = seq; // 被动连接不加1
passive_conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("✅ 收到第三次握手ACK,连接完全建立(%s:%d -> %s:%d)✅\n",
src_ip_str, src_port, dst_ip_str, dst_port);
return;
} else {
printf("⚠️ ACK号不匹配,三次握手失败(期望:%u,实际:%u)⚠️\n",
passive_conn->seq + 1, ack);
}
}
// 场景2:ACK包用于确认关闭连接
else if (active_conn) {
if (active_conn->state == TCP_STATE_FIN_WAIT1) {
tcp_table_update_state(gPortIpAddr, src_ip, dst_port, src_port, TCP_STATE_FIN_WAIT2);
pthread_mutex_lock(&g_tcp_table.mutex);
active_conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("📩 收到ACK包,状态更新为FIN_WAIT2 📩\n");
} else if (active_conn->state == TCP_STATE_FIN_WAIT2) {
tcp_table_update_state(gPortIpAddr, src_ip, dst_port, src_port, TCP_STATE_CLOSED);
printf("📩 收到ACK包,主动连接关闭 📩\n");
}
} else if (passive_conn) {
if (passive_conn->state == TCP_STATE_FIN_WAIT1) {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_FIN_WAIT2);
pthread_mutex_lock(&g_tcp_table.mutex);
passive_conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("📩 收到ACK包,状态更新为FIN_WAIT2 📩\n");
} else if (passive_conn->state == TCP_STATE_FIN_WAIT2) {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_CLOSED);
printf("📩 收到ACK包,被动连接关闭 📩\n");
}
}
}
// 处理数据报文(核心修复:区分主动/被动连接的seq逻辑)
else if (data_len > 0 && flags & RTE_TCP_ACK_FLAG) {
tcp_conn_entry_t *conn = active_conn ? active_conn : passive_conn;
// 允许SYN_RECV状态接收数据(先完成三次握手)
if (passive_conn && passive_conn->state == TCP_STATE_SYN_RECV) {
// 先完成三次握手
if (ack == (passive_conn->seq + 1)) {
tcp_table_update_state(src_ip, gPortIpAddr, src_port, dst_port, TCP_STATE_ESTABLISHED);
// 被动连接 recv_next_seq = seq
pthread_mutex_lock(&g_tcp_table.mutex);
passive_conn->ack = seq + 1;
passive_conn->recv_next_seq = seq; // 被动连接不加1
passive_conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("✅ 收到数据+ACK,完成三次握手,连接建立 ✅\n");
conn = passive_conn; // 重置conn为已建立的连接
} else {
printf("⚠️ ACK号不匹配,无法完成三次握手(期望:%u,实际:%u)⚠️\n",
passive_conn->seq + 1, ack);
return;
}
}
if (conn && conn->state == TCP_STATE_ESTABLISHED) {
// 初始化期望seq(首次接收,兜底逻辑:区分主动/被动)
if (conn->recv_next_seq == 0) {
conn->recv_next_seq = (active_conn ? seq + 1 : seq);
}
// 处理有序数据(此时seq已匹配)
if (seq == conn->recv_next_seq) {
// 将数据写入接收缓冲区(避免粘包)
if (conn->recv_buf_len + data_len < sizeof(conn->recv_buf)) {
memcpy(conn->recv_buf + conn->recv_buf_len, data, data_len);
conn->recv_buf_len += data_len;
conn->recv_next_seq += data_len;
// 打印完整的接收缓冲区数据
printf("📩 接收缓冲区完整数据:%.*s(总长度:%d)📩\n",
conn->recv_buf_len, conn->recv_buf, conn->recv_buf_len);
} else {
printf("⚠️ 接收缓冲区已满,丢弃数据 ⚠️\n");
return;
}
// 正确回复ACK:ack = 期望的下一个seq
uint32_t ack_num = conn->recv_next_seq;
send_tcp_packet(src_ip, src_port, dst_port, conn->seq, ack_num, RTE_TCP_ACK_FLAG, NULL, 0);
// 更新连接状态
pthread_mutex_lock(&g_tcp_table.mutex);
conn->ack = ack_num;
conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("📩 已回复ACK(ack=%u)📩\n", ack_num);
// ========== 新增:尝试合并缓存的乱序包 ==========
#define OUT_OF_ORDER_CACHE_SIZE 8
static struct {
uint32_t seq;
uint16_t data_len;
uint8_t data[1024];
time_t recv_time;
int valid;
} ooo_cache[OUT_OF_ORDER_CACHE_SIZE] = {0};
// 检查缓存中是否有连续的乱序包
for (int k = 0; k < OUT_OF_ORDER_CACHE_SIZE; k++) {
if (ooo_cache[k].valid && ooo_cache[k].seq == conn->recv_next_seq) {
// 合并缓存的乱序包
if (conn->recv_buf_len + ooo_cache[k].data_len < sizeof(conn->recv_buf)) {
memcpy(conn->recv_buf + conn->recv_buf_len, ooo_cache[k].data, ooo_cache[k].data_len);
conn->recv_buf_len += ooo_cache[k].data_len;
conn->recv_next_seq += ooo_cache[k].data_len;
printf("📦 合并缓存的乱序包:%.*s(总长度:%d)📦\n",
ooo_cache[k].data_len, ooo_cache[k].data, conn->recv_buf_len);
// 回复ACK
ack_num = conn->recv_next_seq;
send_tcp_packet(src_ip, src_port, dst_port, conn->seq, ack_num, RTE_TCP_ACK_FLAG, NULL, 0);
pthread_mutex_lock(&g_tcp_table.mutex);
conn->ack = ack_num;
pthread_mutex_unlock(&g_tcp_table.mutex);
// 清空该缓存项
ooo_cache[k].valid = 0;
}
}
}
} else {
// ========== 乱序包缓存逻辑 ==========
#define OUT_OF_ORDER_CACHE_SIZE 8
static struct {
uint32_t seq;
uint16_t data_len;
uint8_t data[1024];
time_t recv_time;
int valid;
} ooo_cache[OUT_OF_ORDER_CACHE_SIZE] = {0};
// 检查是否已缓存
int ooo_exists = 0;
for (int k = 0; k < OUT_OF_ORDER_CACHE_SIZE; k++) {
if (ooo_cache[k].valid && ooo_cache[k].seq == seq) {
ooo_exists = 1;
break;
}
}
if (!ooo_exists) {
// 缓存乱序包
for (int k = 0; k < OUT_OF_ORDER_CACHE_SIZE; k++) {
if (!ooo_cache[k].valid) {
ooo_cache[k].seq = seq;
ooo_cache[k].data_len = data_len;
memcpy(ooo_cache[k].data, data, data_len);
ooo_cache[k].recv_time = now;
ooo_cache[k].valid = 1;
printf("📦 缓存乱序包(seq:%u,长度:%d)📦\n", seq, data_len);
break;
}
}
}
printf("⚠️ 收到乱序TCP包(期望seq:%u,实际:%u),已缓存 ⚠️\n", conn->recv_next_seq, seq);
// 回复ACK(避免对方重传)
send_tcp_packet(src_ip, src_port, dst_port, conn->seq, conn->recv_next_seq, RTE_TCP_ACK_FLAG, NULL, 0);
pthread_mutex_lock(&g_tcp_table.mutex);
conn->last_active = now;
pthread_mutex_unlock(&g_tcp_table.mutex);
}
} else {
printf("⚠️ 收到数据但连接未建立/无对应连接,忽略 ⚠️\n");
}
}
// 处理RST包(优化:详细日志+安全清理)
else if (flags & RTE_TCP_RST_FLAG) {
tcp_conn_entry_t *conn = active_conn ? active_conn : passive_conn;
if (conn) {
printf("📩 收到RST包(强制关闭),连接:%s:%d -> %s:%d 📩\n",
src_ip_str, src_port, dst_ip_str, dst_port);
// 安全清理连接(重置所有状态)
if (active_conn) {
tcp_table_reset_entry(gPortIpAddr, src_ip, dst_port, src_port);
} else {
tcp_table_reset_entry(src_ip, gPortIpAddr, src_port, dst_port);
}
// 打印RST原因提示
printf("⚠️ 连接被对方强制重置,可能原因:\n");
printf(" 1. 序列号不匹配(期望:%u,实际:%u)\n", conn->recv_next_seq, seq);
printf(" 2. 数据长度超出MSS限制\n");
printf(" 3. 对方主动关闭连接\n");
} else {
printf("⚠️ 收到RST包但无对应连接,忽略 ⚠️\n");
}
}
// 处理未知类型的TCP包
else {
printf("⚠️ 收到未处理的TCP包(标志位:0x%02x),忽略 ⚠️\n", flags);
}
}
// ====================== 命令行交互线程 ======================
void *cli_thread_func(__attribute__((unused)) void *arg) {
char input[512];
char cmd[256], param[256];
char ip_str[32], payload[1024];
uint16_t sport, dport;
printf("\n==============================================\n");
printf(" DPDK 交互式网络工具\n");
printf("==============================================\n");
printf("命令列表:\n");
printf(" arp <IP地址> - 发送ARP请求并更新ARP表\n");
printf(" arp show - 显示当前ARP表\n");
printf(" udp <IP> <DPORT> <SPORT> <负载> - 发送UDP包\n");
printf(" ping <IP地址> - 主动Ping目标IP\n");
printf(" clear - 清理过期ARP条目\n");
printf(" tcp connect <IP> <DPORT> <SPORT> - 建立TCP连接\n");
printf(" tcp send <IP> <DPORT> <SPORT> <数据> - 发送TCP数据\n");
printf(" tcp close <IP> <DPORT> <SPORT> - 关闭TCP连接\n");
printf(" tcp show - 显示TCP连接表\n");
printf(" quit/exit - 退出程序\n");
printf("==============================================\n\n");
while (g_running) {
printf("dpdk-cli> ");
fflush(stdout);
// 读取输入
if (fgets(input, sizeof(input), stdin) == NULL) { // 阻塞,不会CPU空转
continue;
}
// 去除换行符
input[strcspn(input, "\n")] = '\0';
// 空输入跳过
if (strlen(input) == 0) {
continue;
}
// 解析命令
memset(cmd, 0, sizeof(cmd));
memset(param, 0, sizeof(param));
sscanf(input, "%s %[^\n]", cmd, param);
if (strcmp(cmd, "arp") == 0) {
// ARP命令
if (strcmp(param, "show") == 0) {
arp_table_print();
} else if (strlen(param) > 0) {
// 发送ARP请求
uint32_t target_ip = inet_addr(param);
if (target_ip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
// 多次重试发送ARP请求
for (int i = 0; i < ARP_REQUEST_RETRY; i++) {
send_arp_request(target_ip);
sleep(ARP_REQUEST_INTERVAL);
// 检查是否已获取到MAC
struct rte_ether_addr mac;
if (arp_table_lookup(target_ip, &mac) == 0) {
break;
}
}
}
} else {
printf("❌ ARP命令用法:arp <IP地址> 或 arp show ❌\n");
}
} else if (strcmp(cmd, "udp") == 0) {
// UDP命令
memset(ip_str, 0, sizeof(ip_str));
memset(payload, 0, sizeof(payload));
int ret = sscanf(param, "%s %hu %hu %[^\n]", ip_str, &dport, &sport, payload);
if (ret < 3) {
printf("❌ UDP命令用法:udp <IP> <目标端口> <源端口> <负载> ❌\n");
printf(" 示例:udp 192.168.3.1 8080 12345 hello_world ❌\n");
} else {
uint32_t dip = inet_addr(ip_str);
if (dip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
send_udp_packet(dip, dport, sport, (uint8_t*)payload, strlen(payload));
}
}
} else if (strcmp(cmd, "ping") == 0) {
// Ping命令
if (strlen(param) == 0) {
printf("❌ Ping命令用法:ping <IP地址> ❌\n");
printf(" 示例:ping 192.168.3.1 ❌\n");
} else {
uint32_t target_ip = inet_addr(param);
if (target_ip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
ping_target(target_ip);
}
}
} else if (strcmp(cmd, "tcp") == 0) {
// TCP命令
char sub_cmd[32];
memset(sub_cmd, 0, sizeof(sub_cmd));
sscanf(param, "%s", sub_cmd);
if (strcmp(sub_cmd, "connect") == 0) {
memset(ip_str, 0, sizeof(ip_str));
int ret = sscanf(param, "%*s %s %hu %hu", ip_str, &dport, &sport);
if (ret < 3) {
printf("❌ TCP连接用法:tcp connect <IP> <目标端口> <源端口> ❌\n");
printf(" 示例:tcp connect 192.168.3.1 8080 12345 ❌\n");
} else {
uint32_t dip = inet_addr(ip_str);
if (dip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
tcp_connect(dip, dport, sport);
}
}
} else if (strcmp(sub_cmd, "send") == 0) {
memset(ip_str, 0, sizeof(ip_str));
memset(payload, 0, sizeof(payload));
int ret = sscanf(param, "%*s %s %hu %hu %[^\n]", ip_str, &dport, &sport, payload);
if (ret < 4) {
printf("❌ TCP发送用法:tcp send <IP> <目标端口> <源端口> <数据> ❌\n");
printf(" 示例:tcp send 192.168.3.1 8080 12345 hello_tcp ❌\n");
} else {
uint32_t dip = inet_addr(ip_str);
if (dip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
tcp_send_data(dip, dport, sport, (uint8_t*)payload, strlen(payload));
}
}
} else if (strcmp(sub_cmd, "close") == 0) {
memset(ip_str, 0, sizeof(ip_str));
int ret = sscanf(param, "%*s %s %hu %hu", ip_str, &dport, &sport);
if (ret < 3) {
printf("❌ TCP关闭用法:tcp close <IP> <目标端口> <源端口> ❌\n");
printf(" 示例:tcp close 192.168.3.1 8080 12345 ❌\n");
} else {
uint32_t dip = inet_addr(ip_str);
if (dip == INADDR_NONE) {
printf("❌ 无效的IP地址格式 ❌\n");
} else {
tcp_close(dip, dport, sport);
}
}
} else if (strcmp(sub_cmd, "show") == 0) {
tcp_table_print();
} else {
printf("❌ 未知TCP子命令:%s ❌\n", sub_cmd);
printf(" 可用子命令:connect, send, close, show ❌\n");
}
}
else if (strcmp(cmd, "clear") == 0) {
// 清理过期ARP条目
arp_table_clean_expired();
}// 在CLI处理逻辑中添加
else if (strncmp(input, "tcp clean", 8) == 0) {
char state_str[32] = {0};
sscanf(input + 9, "%s", state_str);
pthread_mutex_lock(&g_tcp_table.mutex);
int cleaned = 0;
for (int i = 0; i < TCP_TABLE_MAX_ENTRY; i++) {
tcp_conn_entry_t *entry = &g_tcp_table.entries[i];
if (!entry->valid) continue;
if (strcmp(state_str, "time_wait") == 0 && entry->state == TCP_STATE_TIME_WAIT) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
} else if (strcmp(state_str, "syn_recv") == 0 && entry->state == TCP_STATE_SYN_RECV) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
} else if (strcmp(state_str, "all") == 0) {
memset(entry, 0, sizeof(tcp_conn_entry_t));
cleaned++;
}
}
pthread_mutex_unlock(&g_tcp_table.mutex);
printf("✅ 手动清理了%d个%s状态的TCP连接 ✅\n", cleaned, state_str);
}
else if (strcmp(cmd, "help") == 0) {
// 新增help命令逻辑
printf("\n==============================================\n");
printf(" DPDK 交互式网络工具 - 帮助\n");
printf("==============================================\n");
printf("命令列表:\n");
printf(" arp <IP地址> - 发送ARP请求并更新ARP表\n");
printf(" arp show - 显示当前ARP表\n");
printf(" udp <IP> <DPORT> <SPORT> <负载> - 发送UDP包\n");
printf(" ping <IP地址> - 主动Ping目标IP\n");
printf(" clear - 清理过期ARP条目\n");
printf(" tcp connect <IP> <DPORT> <SPORT> - 建立TCP连接\n");
printf(" tcp send <IP> <DPORT> <SPORT> <数据> - 发送TCP数据\n");
printf(" tcp close <IP> <DPORT> <SPORT> - 关闭TCP连接\n");
printf(" tcp show - 显示TCP连接表\n");
printf(" help - 查看帮助信息\n");
printf(" quit/exit - 退出程序\n");
printf("==============================================\n\n");
}else if (strcmp(cmd, "quit") == 0 || strcmp(cmd, "exit") == 0) {
// 退出程序
printf("\n👋 正在退出程序...\n");
g_running = 0;
break;
} else {
printf("❌ 未知命令:%s ❌\n", cmd);
printf(" 输入 'help' 查看命令列表 ❌\n");
}
}
return NULL;
}
// ====================== 主函数 ======================
int main(int argc, char *argv[]) {
// 1. 初始化EAL
int eal_ret = rte_eal_init(argc, argv);
if (eal_ret < 0) {
rte_exit(EXIT_FAILURE, "Error with EAL init\n");
}
argc -= eal_ret;
argv += eal_ret;
// 2. 创建MBUF池
g_mbuf_pool = rte_pktmbuf_pool_create(
"mbuf pool", NUM_MBUFS, 0, 0, RTE_MBUF_DEFAULT_BUF_SIZE, rte_socket_id()
);
if (g_mbuf_pool == NULL) {
rte_exit(EXIT_FAILURE, "Could not create mbuf pool\n");
}
// 3. 初始化端口
ustack_init_port(g_mbuf_pool);
// 4. 初始化ARP表和TCP表
arp_table_init();
tcp_table_init();
// 5. 初始化Ping上下文互斥锁
pthread_mutex_init(&g_ping_mutex, NULL);
// 6. 创建命令行交互线程
pthread_t cli_thread;
if (pthread_create(&cli_thread, NULL, cli_thread_func, NULL) != 0) {
rte_exit(EXIT_FAILURE, "Could not create CLI thread\n");
}
// 7. 主循环收包(优化:动态休眠,平衡实时性和CPU占用)
printf("\n🔄 开始数据包监听 🔄\n");
// 替换原重复包检测逻辑
typedef struct {
uint32_t src_ip;
uint32_t dst_ip;
uint16_t src_port;
uint16_t dst_port;
uint32_t seq;
uint16_t data_len; // 新增:数据长度
time_t recv_time;
} tcp_packet_cache_t;
// 动态休眠控制变量
uint32_t empty_recv_count = 0;
const uint32_t MAX_EMPTY_BEFORE_SLEEP = 5;
const useconds_t MIN_SLEEP_US = 1000;
const useconds_t MAX_SLEEP_US = 10000;
// 主函数中收包循环部分(替换原重复包缓存定义)
while (g_running) {
struct rte_mbuf *mbufs[BURST_SIZE] = {0};
// 收包(非阻塞)
uint16_t num_recvd = rte_eth_rx_burst(global_portid, 0, mbufs, BURST_SIZE);
if (num_recvd > BURST_SIZE) {
rte_exit(EXIT_FAILURE, "Error receiving from eth\n");
}
// 处理每个包
if (num_recvd > 0) {
empty_recv_count = 0;
for (int i = 0; i < num_recvd; i++) {
struct rte_ether_hdr *ethhdr = rte_pktmbuf_mtod(mbufs[i], struct rte_ether_hdr *);
// 处理ARP包
if (ethhdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_ARP)) {
struct rte_arp_hdr *ahdr = (struct rte_arp_hdr *)(ethhdr + 1);
if (ahdr->arp_opcode == htons(RTE_ARP_OP_REPLY)) {
handle_arp_response(ahdr, ethhdr);
}
}
// 处理IP包(包含ICMP、UDP、TCP)
else if (ethhdr->ether_type == rte_cpu_to_be_16(RTE_ETHER_TYPE_IPV4)) {
struct rte_ipv4_hdr *iphdr = (struct rte_ipv4_hdr *)(ethhdr + 1);
// 处理ICMP协议
if (iphdr->next_proto_id == IPPROTO_ICMP) {
struct rte_icmp_hdr *icmphdr = (struct rte_icmp_hdr *)(iphdr + 1);
if (icmphdr->icmp_type == RTE_IP_ICMP_ECHO_REQUEST) {
handle_icmp_echo_request(ethhdr, iphdr, icmphdr);
} else if (icmphdr->icmp_type == RTE_IP_ICMP_ECHO_REPLY) {
handle_icmp_echo_reply(icmphdr, iphdr);
} else if (icmphdr->icmp_type == 3) {
struct in_addr src_ip;
src_ip.s_addr = iphdr->src_addr;
printf("⚠️ 收到ICMP不可达报文 from %s(原因:端口未开放)⚠️\n", inet_ntoa(src_ip));
}
}
// 处理UDP协议
else if (iphdr->next_proto_id == IPPROTO_UDP) {
struct rte_udp_hdr *udphdr = (struct rte_udp_hdr *)(iphdr + 1);
handle_udp_packet(ethhdr, iphdr, udphdr);
}
// 处理TCP协议(重复包过滤已移到handle_tcp_packet内部)
else if (iphdr->next_proto_id == IPPROTO_TCP) {
struct rte_tcp_hdr *tcphdr = (struct rte_tcp_hdr *)(iphdr + 1);
handle_tcp_packet(ethhdr, iphdr, tcphdr);
}
}
// 释放MBUF
rte_pktmbuf_free(mbufs[i]);
}
} else {
empty_recv_count++;
if (empty_recv_count >= MAX_EMPTY_BEFORE_SLEEP) {
useconds_t sleep_us = MIN_SLEEP_US + (empty_recv_count - MAX_EMPTY_BEFORE_SLEEP) * 1000;
if (sleep_us > MAX_SLEEP_US) {
sleep_us = MAX_SLEEP_US;
}
usleep(sleep_us);
}
}
// 定期清理过期ARP条目和无效TCP连接
static time_t last_arp_clean = 0;
static time_t last_tcp_clean = 0;
time_t now = time(NULL);
if (now - last_arp_clean > 60) {
arp_table_clean_expired();
last_arp_clean = now;
}
if (now - last_tcp_clean > TCP_CLOSED_CLEAN_INTERVAL) {
tcp_table_clean_invalid();
last_tcp_clean = now;
}
}
// 等待CLI线程退出
pthread_join(cli_thread, NULL);
// 清理资源
rte_eth_dev_stop(global_portid);
rte_eth_dev_close(global_portid);
rte_mempool_free(g_mbuf_pool);
pthread_mutex_destroy(&g_ping_mutex);
printf("✅ 程序正常退出 ✅\n");
return 0;
}
2.Makefile
cpp
# SPDX-License-Identifier: BSD-3-Clause
# Copyright(c) 2010-2014 Intel Corporation
# binary name
APP = tcp
# all source are stored in SRCS-y
SRCS-y := tcp.c
# Build using pkg-config variables if possible
ifeq ($(shell pkg-config --exists libdpdk && echo 0),0)
all: shared
.PHONY: shared static
shared: build/$(APP)-shared
ln -sf $(APP)-shared build/$(APP)
static: build/$(APP)-static
ln -sf $(APP)-static build/$(APP)
PKGCONF=pkg-config --define-prefix
PC_FILE := $(shell $(PKGCONF) --path libdpdk)
CFLAGS += -O3 $(shell $(PKGCONF) --cflags libdpdk)
CFLAGS += -DALLOW_EXPERIMENTAL_API
LDFLAGS_SHARED = $(shell $(PKGCONF) --libs libdpdk)
LDFLAGS_STATIC = -Wl,-Bstatic $(shell $(PKGCONF) --static --libs libdpdk)
build/$(APP)-shared: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_SHARED)
build/$(APP)-static: $(SRCS-y) Makefile $(PC_FILE) | build
$(CC) $(CFLAGS) $(SRCS-y) -o $@ $(LDFLAGS) $(LDFLAGS_STATIC)
build:
@mkdir -p $@
.PHONY: clean
clean:
rm -f build/$(APP) build/$(APP)-static build/$(APP)-shared
test -d build && rmdir -p build || true
else # Build using legacy build system
ifeq ($(RTE_SDK),)
$(error "Please define RTE_SDK environment variable")
endif
# Default target, detect a build directory, by looking for a path with a .config
RTE_TARGET ?= $(notdir $(abspath $(dir $(firstword $(wildcard $(RTE_SDK)/*/.config)))))
include $(RTE_SDK)/mk/rte.vars.mk
ifneq ($(CONFIG_RTE_EXEC_ENV_LINUX),y)
$(error This application can only operate in a linux environment, \
please change the definition of the RTE_TARGET environment variable)
endif
CFLAGS += -O3
CFLAGS += -DALLOW_EXPERIMENTAL_API
CFLAGS += $(WERROR_FLAGS)
include $(RTE_SDK)/mk/rte.extapp.mk
endif
3.代码讲解
在原有 ARP 表管理 + ICMP/UDP 基础上,新增了完整的 TCP 协议栈核心能力(支持主动建立连接、被动响应连接、数据收发、连接断开、乱序包处理等)。以下是 TCP 模块的核心流程和关键模块详解:
TCP 模块核心流程
main() // 程序入口(仅展示TCP相关部分)
├─ tcp_table_init() // 1. 初始化TCP连接表(32个条目,默认CLOSED,初始化互斥锁+接收缓冲区)
├─ pthread_create() // 2. 命令行交互线程新增TCP子命令:connect/send/close/show/clean
└─ 无限循环(核心:批量收包+TCP包处理)
├─ rte_eth_rx_burst() // 批量接收数据包
├─ 遍历每个收包
│ ├─ 解析以太头→IPv4头→过滤TCP包(next_proto_id=IPPROTO_TCP)
│ ├─ handle_tcp_packet() // 核心:处理TCP包(三次握手/数据收发/四次挥手/RST处理)
│ │ ├─ 重复包过滤(基于src/dst IP+端口+seq+数据长度,3秒缓存)
│ │ ├─ 处理SYN包(被动建立连接→回复SYN+ACK)
│ │ ├─ 处理SYN+ACK包(完成主动连接三次握手→回复ACK)
│ │ ├─ 处理ACK包(完成三次握手/确认关闭)
│ │ ├─ 处理数据包(有序接收/乱序缓存/粘包处理→回复ACK)
│ │ ├─ 处理FIN包(四次挥手→回复ACK+FIN)
│ │ └─ 处理RST包(强制关闭连接→清理连接条目)
│ └─ rte_pktmbuf_free() // 释放MBUF
└─ 定期清理无效TCP连接(每10秒)
├─ 清理CLOSED状态条目(超过10秒)
├─ 清理TIME_WAIT状态条目(超过60秒)
└─ 清理SYN_RECV半连接(超过10秒未完成三次握手)
TCP 关键模块详解
1. TCP 连接表管理模块(核心基础)
tcp_table_t(全局TCP连接表)
├─ tcp_table_init() // 初始化:32个条目,默认valid=0/state=CLOSED,初始化接收缓冲区(4096字节)
├─ tcp_table_add() // 添加连接条目
│ ├─ 查找空条目,填充src/dst IP+端口、状态、随机seq(generate_seq_num())
│ ├─ 记录最后活动时间,初始化互斥锁保证线程安全
│ └─ 表满则返回错误
├─ tcp_table_lookup() // 查找连接条目
│ ├─ 按src/dst IP+端口匹配,忽略CLOSED状态
│ ├─ 加锁保证多线程安全
│ └─ 返回匹配的连接条目指针(NULL=未找到)
├─ tcp_table_update_state() // 更新连接状态
│ ├─ 匹配连接条目→修改state→更新最后活动时间
│ └─ 支持状态:CLOSED/SYN_SENT/ESTABLISHED/FIN_WAIT1/FIN_WAIT2/TIME_WAIT/SYN_RECV
├─ tcp_table_reset_entry() // 重置连接条目(彻底清空,区别于仅改状态)
├─ tcp_table_clean_invalid() // 清理无效连接
│ ├─ 清理CLOSED条目(超过10秒)
│ ├─ 清理TIME_WAIT条目(标准60秒超时)
│ ├─ 清理SYN_RECV半连接(10秒未完成三次握手)
│ └─ 打印清理数量,保证连接表整洁
└─ tcp_table_print() // 打印连接表
├─ 显示源IP/端口、目标IP/端口、连接状态
└─ 格式化输出,便于调试
2. TCP 数据包编解码模块(收发基础)
├─ tcp_checksum() // 计算TCP校验和(含伪头部:源/目标IP+协议号+TCP长度)
│ ├─ 先计算伪头部校验和,再计算TCP头+数据校验和
│ └─ 折叠校验和(高16位+低16位)→ 取反得到最终值
├─ encode_tcp_packet() // 编码TCP数据包
│ ├─ 以太头:从ARP表获取目标MAC,源MAC为本机
│ ├─ IPv4头:版本4+头长20字节,TTL=64,协议=TCP,自动计算IP校验和
│ ├─ TCP头:源/目标端口、seq/ack、标志位(SYN/ACK/FIN/RST)、窗口大小(65535)
│ ├─ 拷贝负载数据(如有)
│ └─ 计算并填充TCP校验和
└─ send_tcp_packet() // 发送TCP数据包
├─ 查找ARP表获取目标MAC(失败则返回错误)
├─ 分配MBUF,调用encode_tcp_packet()编码
├─ rte_eth_tx_burst()发送(单次1个包)
└─ 打印发送信息(目标IP+端口、标志位、seq/ack、负载长度)
3. TCP 主动连接管理模块(三次握手 / 数据发送 / 四次挥
├─ tcp_connect() // 主动建立TCP连接(三次握手)
│ ├─ 先发送ARP请求获取目标MAC(重试3次)
│ ├─ 添加连接条目(状态=SYN_SENT)
│ ├─ 发送SYN包(第一次握手,重试3次,每次生成新seq)
│ ├─ 等待SYN+ACK响应(超时3秒)
│ ├─ 收到SYN+ACK后回复ACK(第三次握手),更新状态=ESTABLISHED
│ └─ 超时则清理连接条目,返回失败
├─ tcp_send_data() // 发送TCP数据(仅ESTABLISHED状态)
│ ├─ 查找有效连接(状态=ESTABLISHED)
│ ├─ 基于当前seq/ack发送数据(带ACK标志)
│ ├─ 更新本地seq(seq += 数据长度)
│ └─ 打印发送数据信息(目标IP+端口、数据长度/内容)
└─ tcp_close() // 主动关闭TCP连接(四次挥手)
├─ 查找有效连接,更新状态=FIN_WAIT1
├─ 发送FIN+ACK包(第一次挥手)
├─ 等待响应(超时6秒)
└─ 无论是否超时,彻底清理连接条目
4. TCP 被动包处理模块(核心逻辑)
handle_tcp_packet() // 处理收到的TCP包
├─ 前置过滤:仅处理目标IP为本机的TCP包,解析src/dst IP+端口、seq/ack、标志位、数据
├─ 重复包过滤:缓存32个包(src/dst IP+端口+seq+数据长度),3秒内重复则忽略
├─ 分场景处理:
│ ├─ 处理SYN包(仅SYN):
│ │ ├─ 添加被动连接条目(状态=SYN_RECV)
│ │ ├─ 回复SYN+ACK包(第二次握手)
│ │ └─ 记录我方seq,用于后续验证
│ ├─ 处理SYN+ACK包:
│ │ ├─ 匹配SYN_SENT状态的连接
│ │ ├─ 回复ACK包(第三次握手),更新状态=ESTABLISHED
│ │ └─ 初始化recv_next_seq(对方下一个数据的seq)
│ ├─ 处理ACK包(无数据):
│ │ ├─ 完成被动连接三次握手(验证ack=我方seq+1),更新状态=ESTABLISHED
│ │ ├─ 确认关闭连接(FIN_WAIT1→FIN_WAIT2,FIN_WAIT2→CLOSED)
│ │ └─ 更新最后活动时间
│ ├─ 处理数据包(带ACK标志+数据):
│ │ ├─ 有序数据:写入接收缓冲区,更新recv_next_seq,回复ACK(ack=recv_next_seq)
│ │ ├─ 乱序数据:缓存8个乱序包(seq不匹配),后续有序包到达后自动合并
│ │ ├─ 粘包处理:接收缓冲区累积数据,打印完整缓存内容
│ │ └─ 缓冲区满则丢弃数据,打印警告
│ ├─ 处理FIN包:
│ │ ├─ 回复ACK包(确认关闭)
│ │ ├─ 主动连接:更新状态=TIME_WAIT,回复FIN+ACK
│ │ └─ 被动连接:更新状态=TIME_WAIT,后续自动清理
│ └─ 处理RST包:
│ ├─ 查找对应连接条目,强制设置state=CLOSED、valid=0
│ └─ 打印强制关闭信息,直接返回(不再处理)
└─ 未知包处理:打印警告,忽略
5. TCP 命令行交互模块(用户操作)
cli_thread_func() // 命令行线程新增TCP子命令
├─ "tcp connect <IP> <DPORT> <SPORT>":调用tcp_connect()建立主动连接
├─ "tcp send <IP> <DPORT> <SPORT> <数据>":调用tcp_send_data()发送数据
├─ "tcp close <IP> <DPORT> <SPORT>":调用tcp_close()关闭连接
├─ "tcp show":调用tcp_table_print()打印连接表
├─ "tcp clean <state>":手动清理指定状态的连接
│ ├─ "tcp clean time_wait":清理TIME_WAIT状态
│ ├─ "tcp clean syn_recv":清理SYN_RECV状态
│ └─ "tcp clean all":清理所有连接
└─ 输入校验:检查IP格式、端口范围、参数完整性,错误则提示用法
4.运行案例


