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 客户端!

相关推荐
阿钱真强道1 个月前
29 鸿蒙LiteOS RK2206 Socket编程实战 UDP通信+LWIP原理全解析
udp·socket·鸿蒙·liteos·开源鸿蒙·瑞芯微·rk2206
阿钱真强道1 个月前
25 鸿蒙LiteOS GPIO轮询模式实战教程:电平读取与上升沿检测
嵌入式·harmonyos·liteos·开源鸿蒙·瑞芯微·rk2206
时光飞逝的日子2 个月前
嵌入式低功耗极限优化:从硬件休眠到 AI 推理调度的全栈节能实战
事件驱动·电源管理·tinyml·嵌入式低功耗·dvfs
阿钱真强道2 个月前
24 鸿蒙LiteOS GPIO中断实战:从原理到上升沿/下降沿详解
harmonyos·中断·rk·liteos·开源鸿蒙·瑞芯微·rk2206
阿钱真强道2 个月前
23 鸿蒙LiteOS 消息队列(Queue)实战教程:任务间数据传递详解
harmonyos·鸿蒙·消息·队列·liteos·rk2206·瑞星微
阿钱真强道2 个月前
22 鸿蒙LiteOS 互斥锁(Mutex)实战教程:多任务共享资源保护
harmonyos·鸿蒙·互斥·rk·liteos·瑞芯微·rk2206
阿钱真强道2 个月前
19 小凌派 rk2206 鸿蒙 LiteOS-M 任务详解
华为·鸿蒙·任务·liteos·详解·rk2206·小凌派
阿钱真强道2 个月前
18 小凌派 rk2206 鸿蒙 liteos 如何通过修改配置文件,编译不通的案例
华为·鸿蒙·编译·案例·liteos·rk2206
__土块__2 个月前
AI 后台模型调用额度突降为零的治理复盘:从额度同步延迟到动态感知的稳定性实践
可观测性·系统稳定性·事件驱动·缓存一致性·ai工程·生产实践·额度治理