硬汉嵌入式论坛

 找回密码
 立即注册
查看: 353|回复: 3
收起左侧

[NetX] Netx 中TCP怎么处理粘包,有没有成熟得代码

[复制链接]

31

主题

101

回帖

194

积分

初级会员

积分
194
发表于 2026-1-21 17:26:42 | 显示全部楼层 |阅读模式
Netx 中TCP怎么处理粘包,有没有成熟得代码
回复

使用道具 举报

0

主题

310

回帖

310

积分

高级会员

积分
310
发表于 2026-1-21 18:12:10 | 显示全部楼层
1固定长度数据包,2特定的分隔符号,3加入帧头,包含数据长度
回复

使用道具 举报

30

主题

426

回帖

516

积分

金牌会员

积分
516
发表于 2026-1-22 11:59:05 | 显示全部楼层
本帖最后由 tovinz 于 2026-1-22 12:04 编辑

如果你的协议是自定义的,推荐你用 cobs编解码算法 进行数据包封装和提取。
cobs.c (1.58 KB, 下载次数: 2) cobs.h (836 Bytes, 下载次数: 2)


高效可靠的数据字节编码算法COBS,可用于串口通信
https://forum.anfulai.cn/forum.p ... 15429&fromuid=41790
(出处: 硬汉嵌入式论坛)


下面提供一个字节流数据包提取器组件(根据分割字符进行提取,仅提取,提取后可自行用于对接 cobs 解码)
组件依赖 pipe,其实就是一个环形缓冲区。此组件不依赖 cobs 组件
pipe.c (3.75 KB, 下载次数: 5) pipe.h (2.68 KB, 下载次数: 3) pkt_rx.c (4.06 KB, 下载次数: 5) pkt_rx.h (1.79 KB, 下载次数: 3)

原理很简单,
1. 初始化pipe组件;初始化 pkt_rx 组件,关联pipe组件,配置分隔符、操作缓冲区、超时等信息
1. 将接收到的字节流通过 pkt_rx_feed() 或 pkt_rx_feed_byte() 填充到关联的pipe中
2. 通过不断调用 pkt_rx_next() 来从关联的 pipe 中解析数据包


代码片段
1. 初始化
[C] 纯文本查看 复制代码
 



// 传输接收到的数据的管道
static pipe_t  g_u6_rxpipe;
static uint8_t g_u6_rxpipe_buff[ CONFIG_RX_PIPE_BUFF_SIZE ];

// 接收数据包提取器
#define U6_PKT_SEPARATOR    0x00
static pkt_rx_t g_u6_pkt;
// 存放提取出来的接收数据帧
static uint8_t  g_u6_pkt_fbuf[ CONFIG_FRAM_MAX_LEN + 20 ];

void init (void)
{
    pkt_rx_cfg_t cfg;

    // 初始化pipe
    pipe_init(&g_u6_rxpipe, g_u6_rxpipe_buff, sizeof(g_u6_rxpipe_buff));
    
    // 初始化数据包提取器
    memset(&cfg, 0, sizeof(cfg));
    cfg.pipe       = &g_u6_rxpipe;  // 关联pipe
    cfg.frame_buf  = g_u6_pkt_fbuf; // 用于提取数据包的操作的缓冲区
    cfg.frame_cap  = sizeof(g_u6_pkt_fbuf);
    cfg.separator  = U6_PKT_SEPARATOR; // 字节流中区分数据包的分隔字符
    cfg.timeout_ms = 500; // 超时时间。用于长时间没有数据接收时清理pipe中未成功解析的数据
    pkt_rx_init(&g_u6_pkt, &cfg);
}



2. 数据写入
[C] 纯文本查看 复制代码

    /* 将接收到的数据写入到关联的pipe中 */
    pkt_rx_feed(&g_u6_pkt, d, s);



3. 数据包提取
[C] 纯文本查看 复制代码
// 线程. 从管道中拉取数据, 使用cobs解码


static void u6_rx_thread_entry (void *arg)
{
    // 解码缓冲区
    uint8_t  g_u6_rx_decode[ CONFIG_FRAM_MAX_LEN ];

    size_t frame_len = 0;
    pkt_rx_view_t view;
    
    for (;;)
    {
        osDelay(5);
        
        /* 从管道中拉取数据, 并通过分隔字符机制提取数据包 */
        while (pkt_rx_next(&g_u6_pkt, osKernelGetTickCount(), &view) == PKT_RX_OK)
        {
            /* 使用cobs解码数据包 */
            frame_len = cobsDecode(view.data, view.len, g_u6_rx_decode);
            /* 处理数据包 */
            rx_hook(g_u6_rx_decode, frame_len);
        }
    }
}









回复

使用道具 举报

31

主题

101

回帖

194

积分

初级会员

积分
194
 楼主| 发表于 2026-1-24 08:31:31 | 显示全部楼层
tovinz 发表于 2026-1-22 11:59
如果你的协议是自定义的,推荐你用 cobs编解码算法 进行数据包封装和提取。

谢谢分享
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2026-2-24 15:02 , Processed in 0.068924 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表