packet转发时需注意的报头的几个变量

本文介绍了在网络编程中处理报文的关键步骤,包括设置源目的地址、更新上一跳与下一跳信息、配置报文类型及方向等。这些操作对于确保数据包正确转发至关重要。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

iph->src&dst源目的地址,生成packet时赋值即可

cmn->pre_hop_ cmn->next_hop_

上一跳 &下一条 必要时每次都要更新

cmn->add_type_,在生成报文时赋值即可,(如NS_AF_INET,若不设置在arp地址解析时找不到,则无法转发)

cmn->direction_ ,每次转发时都要设置,否则为HDR::UP;若生成报文时不设置,则为0(enum dir_t { DOWN= -1, NONE= 0, UP= 1 };),既往下层发送,也往上层发送

cmn->num_forwards_标记使用,要加1 iph->ttl类似;

/** * @brief MQTT协议报文解析器 * @param q 循环队列指针,存储待解析的MQTT报文数据 * @param packet_buff 输出缓冲区,用于存储解析出的完整MQTT报文 * @return 解析成功的报文长度(字节数),返回0表示解析失败或数据不足 */ unsigned int mqtt_parser(CircularQueue *q, uint8_t *packet_buff) { // 静态变量:跨函数调用保持状态 static uint8_t state = 0; // 解析状态机当前状态 static uint32_t total_length = 0; // 待解析报文的总长度(固定报头+剩余长度+负载) static uint8_t remaining_length_bytes = 0; // 剩余长度字段占用的字节数 static uint8_t time_out = 0; // 超计数器(连续未完整解析的次数) // 局部变量 uint8_t packet_type; // MQTT报文类型(存储在固定报头的第1个字节) uint8_t byte; // 临存储从队列读取的字节 uint8_t multiplier; // 剩余长度解码的乘数(1, 128, 128^2, 128^3) uint8_t remaining_length; // 解析出的剩余长度值(不包含固定报头和剩余长度字段本身) uint32_t current_offset; // 当前正在解析的字节在队列中的偏移量 uint32_t i; // 循环计数器 while (1) { // 检查队列中是否有足够的基础数据(至少需要2字节才能开始解析) if (Queue_Length(q) < 2) { return 0; // 数据不足,等待更多数据 } // 状态机处理 switch (state) { case 0: // 解析固定报头和剩余长度 // 读取固定报头的第1个字节(包含报文类型和标志位) Queue_PeekAt(q, 0, &packet_type); LOG_PRINTF("[MQTT Parser] Processing packet type: 0x%02X\n", packet_type); // 验证报文类型是否合法 if (!validate_packet_header(packet_type)) { LOG_PRINTF("[MQTT Parser] Invalid packet header: 0x%02X\n", packet_type); Queue_MoveReadIndex(q, 1); // 丢弃无效字节 state = 0; time_out = 0; return 0; } // 初始化剩余长度解析相关变量 multiplier = 1; // 初始乘数为1(128^0) total_length = 0; // 重置总长度 remaining_length_bytes = 0; // 重置剩余长度字节计数器 remaining_length = 0; // 重置剩余长度值 // 解析剩余长度字段(可能占用1~4字节) do { // 检查队列中是否有足够数据读取下一个剩余长度字节 if (Queue_Length(q) < (1 + remaining_length_bytes + 1)) { return 0; // 数据不足,等待更多数据 } // 计算当前剩余长度字节的偏移量(固定报头1字节 + 已解析的剩余长度字节数) current_offset = 1 + remaining_length_bytes; Queue_PeekAt(q, current_offset, &byte); // 读取当前剩余长度字节 // 解码剩余长度值(每个字节的低7位是有效数据,最高位是继续标志) remaining_length += (byte & 0x7F) * multiplier; multiplier *= 128; // 乘数递增(1, 128, 128^2, 128^3) remaining_length_bytes++; // 剩余长度字节计数器递增 // 协议合规性检查:剩余长度最多占用4字节 if (remaining_length_bytes >= 4 && (byte & 0x80)) { LOG_PRINTF("[MQTT Parser] Invalid remaining length (exceeds 4 bytes)\n"); Queue_MoveReadIndex(q, 1 + remaining_length_bytes); // 丢弃错误报文 state = 0; time_out = 0; return 0; } } while (byte & 0x80); // 继续循环直到遇到剩余长度的最后一个字节(最高位为0) // 计算完整报文长度:固定报头(1字节) + 剩余长度字节数 + 剩余长度值 total_length = 1 + remaining_length_bytes + remaining_length; LOG_PRINTF("[MQTT Parser] Packet length: %u bytes\n", total_length); state = 1; break; case 1: // 检查数据是否完整、超处理 // 检查队列中是否有完整的报文数据 if (Queue_Length(q) < total_length) { // 超处理:给一个比较长的超间,如果队列中的数据量都还达不到报文长度,则丢弃所有数据 time_out++; if (time_out >= MAX_TIMEOUT_COUNT) { if(Queue_Length(q) < total_length) { LOG_PRINTF("[MQTT Parser] Timeout, discard all byte\n"); Queue_MoveReadIndex(q, Queue_Length(q)); // 移动读指针,丢弃当前队列中所有数据 state = 0; // 重置状态机 time_out = 0; // 重置超计数器 return 0; } } return 0; // 数据不足,等待更多数据 } else // 数据完整,准备读取完整数据 { state = 2; break; } case 2: // 读取完整报文 // 批量读取报文数据到输出缓冲区 for (i = 0; i < total_length; i++) { Queue_PeekAt(q, i, &packet_buff[i]); LOG_PRINTF("%02X ", packet_buff[i]); // 调试输出:打印报文字节 } printf("\n"); // 移动队列读指针,丢弃已读取的报文数据 Queue_MoveReadIndex(q, total_length); // 重置状态机和超计数器 state = 0; time_out = 0; // 返回解析成功的报文长度 return total_length; default: // 未知状态,重置状态机 LOG_PRINTF("[MQTT Parser] Unknown state, resetting\n"); state = 0; time_out = 0; return 0; } } }如何在case0中增加数据不足的超处理,检查这个代码逻辑,和其他错误,给出完整代码,
最新发布
07-12
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值