• Lwip之TCP客户端示例记录


    前言

    1. 使用两个线程作为客户端中的收和发
    2. 使用线程挂起和线程恢复的api来实现
    3. 接收线程必须要保证在处理连接状态才能进行接收。

    Demo

    //
    // Created by shchl on 2024/3/8.
    //
    #include 
    #include "lwip/api.h"
    #include "FreeRTOS.h"
    #include "task.h"
    
    #define TCP_CLIENT_RX_BUFSIZE 256
    
    static void tcp_client_send(void *);
    
    static void tcp_client_rec(void *);
    
    static TaskHandle_t client_send_handle;
    static TaskHandle_t client_rec_handle;
    static ip_addr_t server_ipaddr, loca_ipaddr;
    static uint16_t server_port = 8080;
    static struct netconn *tcp_conn;
    static uint8_t tcp_client_recvbuf[TCP_CLIENT_RX_BUFSIZE] = {0};    //TCP客户端接收数据缓冲区
    
    
    void create_netconn_tcp_client_thread() {
    
        xTaskCreate((TaskFunction_t) tcp_client_send,
                    (const char *) "tcp_client_send",
                    (uint16_t) 256,
                    (void *) NULL,
                    (UBaseType_t) 10,
                    (TaskHandle_t *) &client_send_handle);
    
        xTaskCreate((TaskFunction_t) tcp_client_rec,
                    (const char *) "tcp_client_rec",
                    (uint16_t) 256,
                    (void *) NULL,
                    (UBaseType_t) 11,
                    (TaskHandle_t *) &client_rec_handle);
    
    }
    
    const char *tcp_client_sendbuf = "Apollo STM32F4/F7 NETCONN TCP Client send data\r\n";    //TCP客户端发送数据缓冲区
    static void tcp_client_send(void *arg) {
        err_t err, recv_err;
        IP4_ADDR(&server_ipaddr, 192, 168, 8, 2);
        while (1) {
    
            tcp_conn = netconn_new(NETCONN_TCP);  //创建一个TCP链接
            err = netconn_connect(tcp_conn, &server_ipaddr, server_port);//连接服务器
            if (err != ERR_OK) {
                netconn_delete(tcp_conn); //返回值不等于ERR_OK,删除tcp_clientconn连接
                printf("连接失败....等待重新连接\r\n");
                vTaskDelay(1000);
                continue;
            } else {
                vTaskResume(client_rec_handle);/*恢复接收线程*/
                printf("连接...ok\r\n");
            }
            while (1) {
                err = netconn_write(tcp_conn, tcp_client_sendbuf, strlen((char *) tcp_client_sendbuf),
                                    NETCONN_COPY); //发送tcp_server_sentbuf中的数据
                if (err != ERR_OK) {
                    printf("发送失败\r\n");
                    netconn_close(tcp_conn);
                    netconn_delete(tcp_conn);
                    break;
                }
                vTaskDelay(1000);
            }
        }
    }
    
    static void tcp_client_rec(void *arg) {
        err_t recv_err;
        uint32_t data_len;
        struct pbuf *q;
        struct netbuf *recvbuf;
        vTaskSuspend(client_rec_handle); /*挂起自身线程*/
        while (1) {
            if ((recv_err = netconn_recv(tcp_conn, &recvbuf)) == ERR_OK)  //接收到数据
            {
                portDISABLE_INTERRUPTS(); //关中断
                memset(tcp_client_recvbuf, 0, TCP_CLIENT_RX_BUFSIZE);  //数据接收缓冲区清零
                for (q = recvbuf->p; q != NULL; q = q->next)  //遍历完整个pbuf链表
                {
                    //判断要拷贝到TCP_CLIENT_RX_BUFSIZE中的数据是否大于TCP_CLIENT_RX_BUFSIZE的剩余空间,如果大于
                    //的话就只拷贝TCP_CLIENT_RX_BUFSIZE中剩余长度的数据,否则的话就拷贝所有的数据
                    if (q->len > (TCP_CLIENT_RX_BUFSIZE - data_len))
                        memcpy(tcp_client_recvbuf + data_len, q->payload, (TCP_CLIENT_RX_BUFSIZE - data_len));//拷贝数据
                    else memcpy(tcp_client_recvbuf + data_len, q->payload, q->len);
                    data_len += q->len;
                    if (data_len > TCP_CLIENT_RX_BUFSIZE) break; //超出TCP客户端接收数组,跳出
                }
                portENABLE_INTERRUPTS(); //关中断
                data_len = 0;  //复制完成后data_len要清零。
                printf("%s", tcp_client_recvbuf);
                netbuf_delete(recvbuf);
            } else if (recv_err == ERR_CLSD)  //关闭连接
            {
                printf("服务器%d.%d.%d.%d断开连接\r\n", 192, 168, 8, 2);
                vTaskSuspend(client_rec_handle); /*挂起自身线程*/
            }
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
  • 相关阅读:
    碳排放预测模型 | Python实现基于机器回归分析的碳排放预测模型——数据清理和准备
    省HVV初体验(edu)
    Java开发-应届生面试常常涉及到的问题
    支持JDK19虚拟线程的web框架,之四:看源码,了解quarkus如何支持虚拟线程
    node.js 命令行的命令注册和配置工具(最新版) commander.js 实用教程(含自研脚手架的创建流程)
    Matlab:无穷和 NaN
    桥接设计模式
    实用调试小技巧
    PostgreSQL修炼之道笔记之基础篇(十)
    本草中国-----境界
  • 原文地址:https://blog.csdn.net/weixin_44742767/article/details/136571401