31 LwIP Raw API 搭建TCP客户端

任务十六:LwIP Raw API 搭建TCP客户端

一、任务介绍

1. 本节目标

使用 LwIP Raw API 实现 TCP 客户端,理解事件驱动和流量控制机制。

2. Raw API vs Socket

对比 Socket Raw API
运行机制 业务任务阻塞调用 回调事件驱动
流量控制 内核自动处理 需手动调用 tcp_recved
数据存储 连续缓冲区 pbuf 链表,需手动拼接
内存占用 较高 极低

3. 核心API

API 功能
tcp_new() 创建TCP控制块
tcp_connect() 异步连接服务器
tcp_recved() 通知协议栈已处理数据(流控关键)
tcp_write() 发送数据
tcp_sndbuf() 查询发送缓冲区剩余空间

二、任务实施

2.1 架构设计

复制代码
业务任务:WiFi检测 + 重连 + 定时发送
内核回调:连接成功、数据接收、异常断开
状态机:0-断开 → 1-连接中 → 2-就绪

2.2 完整源码

c 复制代码
#include "ohos_init.h"
#include "los_task.h"
#include "lz_hardware.h"
#include "config_network.h"
#include "lwip/tcp.h"
#include "lwip/ip_addr.h"
#include <stdio.h>
#include <string.h>

#define SERVER_IP "192.168.111.61"
#define SERVER_PORT 20108
#define RECV_BUFFER_SIZE 512

static struct tcp_pcb *g_tpcb = NULL;
static int g_send_cnt = 0;
static int is_connected = 0;

// 接收回调:pbuf链式拼接
static err_t tcp_raw_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)
{
    if (p == NULL) { tcp_close(tpcb); is_connected = 0; return ERR_OK; }
    char recv_buf[RECV_BUFFER_SIZE] = {0};
    int offset = 0;
    struct pbuf *q;
    for (q = p; q && offset < RECV_BUFFER_SIZE - 1; q = q->next) {
        int copy_len = q->len < (RECV_BUFFER_SIZE - 1 - offset) ? q->len : (RECV_BUFFER_SIZE - 1 - offset);
        memcpy(recv_buf + offset, q->payload, copy_len);
        offset += copy_len;
    }
    printf("[RAW RECV] %s\r\n", recv_buf);
    tcp_recved(tpcb, p->tot_len);  // 滑动窗口上报
    pbuf_free(p);
    return ERR_OK;
}

static void tcp_raw_err(void *arg, err_t err)
{
    printf("[ERROR] TCP异常\r\n");
    g_tpcb = NULL;
    is_connected = 0;
}

static err_t tcp_raw_connected(void *arg, struct tcp_pcb *tpcb, err_t err)
{
    if (err != ERR_OK) { tcp_close(tpcb); is_connected = 0; return err; }
    g_tpcb = tpcb;
    tcp_recv(tpcb, tcp_raw_recv);
    tcp_err(tpcb, tcp_raw_err);
    tcp_nagle_disable(tpcb);
    is_connected = 2;
    printf("[SUCCESS] TCP连接成功\r\n");
    return ERR_OK;
}

static void tcp_raw_connect(void)
{
    ip_addr_t server_ip;
    server_ip.addr = inet_addr(SERVER_IP);
    struct tcp_pcb *pcb = tcp_new();
    tcp_connect(pcb, &server_ip, SERVER_PORT, tcp_raw_connected);
    is_connected = 1;
}

static err_t tcp_raw_safe_send(const char *data, u16_t len)
{
    if (!g_tpcb || !data || !len) return ERR_CONN;
    if (tcp_sndbuf(g_tpcb) < len) return ERR_MEM;
    err_t ret = tcp_write(g_tpcb, data, len, TCP_WRITE_FLAG_COPY);
    if (ret == ERR_OK) tcp_output(g_tpcb);
    return ret;
}

void tcp_raw_single_task(unsigned long arg)
{
    WifiLinkedInfo info;
    while (1) {
        if (GetLinkedInfo(&info) != WIFI_SUCCESS || info.connState != WIFI_CONNECTED) {
            LOS_Msleep(1000); continue;
        }
        if (is_connected == 0) tcp_raw_connect();
        if (is_connected == 2) {
            char buf[64];
            snprintf(buf, sizeof(buf), "RK2206 Raw TCP Test:%d\r\n", g_send_cnt++);
            tcp_raw_safe_send(buf, strlen(buf));
        }
        LOS_Msleep(1000);
    }
}

void tcp_client_raw_demo_init(void)
{
    unsigned int task_id;
    TSK_INIT_PARAM_S param = {0};
    param.pfnTaskEntry = (TSK_ENTRY_FUNC)tcp_raw_single_task;
    param.uwStackSize = 10240;
    param.usTaskPrio = 24;
    param.pcName = "tcp_raw_task";
    LOS_TaskCreate(&task_id, &param);
}
APP_FEATURE_INIT(tcp_client_raw_demo_init);

三、任务验证

复制代码
[SUCCESS] TCP Raw客户端连接服务器成功
[RAW SEND] RK2206 Raw TCP Test:0
[RAW RECV] 服务器回复数据

四、常见问题

问题 原因 解决
tcp_write失败 发送缓冲区满 用 tcp_sndbuf 检测
重复收数据 未调用 tcp_recved 接收后必须调用
任务卡死 循环无延时 加 LOS_Msleep 让出CPU

五、任务总结

✅ 掌握 LwIP Raw API TCP 客户端!

相关推荐
做个文艺程序员18 小时前
MinIO第05篇:MinIO事件通知机制与Kafka集成——构建SaaS平台的异步文件处理管道
kafka·消息队列·springboot·minio·事件驱动·异步处理
骑着蜗牛撵大象32720 小时前
SpringBoot+Vue3 企业智能体侧挂架构:独立服务、独立数据库与主线零侵入落地
数据库·spring boot·架构·vue·springboot·事件驱动·服务拆分
EatFan7 天前
2026 后端架构进入 AI 原生阶段:事件驱动 + 虚拟线程 + Agent 内嵌三驾马车怎么落地
人工智能·架构·agent·虚拟线程·事件驱动·ai原生·后端架构
bkspiderx12 天前
Qt 的消息机制:事件驱动与信号槽的底层逻辑
开发语言·qt·信号槽·事件驱动·qt 的消息机制
醉颜凉1 个月前
Redis网络层解析:高性能服务器架构设计与实现
redis·epoll·网络架构·i/o多路复用·事件驱动
阿钱真强道4 个月前
29 鸿蒙LiteOS RK2206 Socket编程实战 UDP通信+LWIP原理全解析
udp·socket·鸿蒙·liteos·开源鸿蒙·瑞芯微·rk2206
阿钱真强道4 个月前
25 鸿蒙LiteOS GPIO轮询模式实战教程:电平读取与上升沿检测
嵌入式·harmonyos·liteos·开源鸿蒙·瑞芯微·rk2206
时光飞逝的日子4 个月前
嵌入式低功耗极限优化:从硬件休眠到 AI 推理调度的全栈节能实战
事件驱动·电源管理·tinyml·嵌入式低功耗·dvfs
阿钱真强道5 个月前
24 鸿蒙LiteOS GPIO中断实战:从原理到上升沿/下降沿详解
harmonyos·中断·rk·liteos·开源鸿蒙·瑞芯微·rk2206