嵌入式上位机开发入门(九):RT-Thread 数据收发代码借鉴

张开发
2026/4/3 14:32:44 15 分钟阅读
嵌入式上位机开发入门(九):RT-Thread 数据收发代码借鉴
目录一、前言二、发送数据三、接收数据四、核心机制后台线程五、总结六、结尾一、前言大家好这里是Hello_Embed。上篇我们分析了 RT-Thread 的 Socket 创建、绑定、监听与连接流程本篇继续借鉴其数据收发的实现为后续用 FreeRTOS 实现做准备。二、发送数据发送数据用到两个函数intat_sendto(intsocket,constvoid*data,size_tsize,intflags,conststructsockaddr*to,socklen_ttolen);intat_send(intsocket,constvoid*data,size_tsize,intflags);send 与 sendto 的区别at_send实际上是对at_sendto的封装intat_send(intsocket,constvoid*data,size_tsize,intflags){returnat_sendto(socket,data,size,flags,RT_NULL,0);}TCP 传输不需要to参数连接已建立UDP 才需要使用to参数指定远端信息。底层实现at_sendto函数内部调用sock-ops-at_sendif((lensock-ops-at_send(sock,(constchar*)data,size,sock-type))0)每个 WiFi 模块的 ops 结构体定义如下structat_socket_ops{int(*at_connect)(structat_socket*socket,char*ip,int32_tport,enumat_socket_typetype,rt_bool_tis_client);int(*at_closesocket)(structat_socket*socket);int(*at_send)(structat_socket*socket,constchar*buff,size_tbfsz,enumat_socket_typetype);int(*at_domain_resolve)(constchar*name,charip[16]);void(*at_set_event_cb)(at_socket_evt_tevent,at_evt_cb_tcb);int(*at_socket)(structat_device*device,enumat_socket_typetype);int(*at_listen)(structat_socket*socket,intbacklog);};虽然不同模块的 AT 命令不同但都是通过at_client_obj_send发送 AT 命令。软件 socket 与硬件 socket 的关系分配的socket整数与device_socket硬件 socket并不相同socketAPP 层的软件概念device_socketWiFi 模块创建连接后的硬件 socket对于 TCP Client调用connect函数后会在user_data记录真正的 hardware socket对于 TCP Server调用accept函数等待连接后会在user_data记录真正的 hardware socket。intdevice_socket(int)socket-user_data;使用 AT 命令发送数据时使用的是硬件 socketdevice_socket而非软件 socket。三、接收数据接收数据用到两个函数intat_recvfrom(intsocket,void*mem,size_tlen,intflags,structsockaddr*from,socklen_t*fromlen);intat_recv(intsocket,void*mem,size_tlen,intflags);recv 与 recvfrom 的区别与发送类似at_recv直接调用at_recvfromintat_recv(ints,void*mem,size_tlen,intflags){returnat_recvfrom(s,mem,len,flags,RT_NULL,RT_NULL);}TCP 建立连接后 socket 已含有远端信息所以from全部设置为 NULL。at_recvfrom 的核心实现while(1){/* wait the receive semaphore */if(rt_sem_take(sock-recv_notice,timeout)0){errnoEAGAIN;result-1;goto__exit;}else{/* get receive buffer to receiver ring buffer */rt_mutex_take(sock-recv_lock,RT_WAITING_FOREVER);recv_lenat_recvpkt_get((sock-recvpkt_list),(char*)mem,len);rt_mutex_release(sock-recv_lock);if(recv_len0){break;}else{errnoEIO;result-1;goto__exit;}}}接收流程分为两步阻塞等待唤醒rt_sem_take(sock-recv_notice, timeout)等待信号量复制数据at_recvpkt_get从recvpkt_list链表中取出数据那么谁唤醒谁给 socket 存入数据答案在后台线程。四、核心机制后台线程对于这样一套通信流程PC — WiFi 模块 — MCU — APP1、APP2PC 作为 Server 给 WiFi 模块串口传输数据最终被对应 APP 读取必然有后台线程做到读 UART解析数据包得到硬件 socket发送与接收数据本身很简单发送就传递 socket接收就阻塞等待唤醒关键在于后台线程。五、总结send vs sendtoat_send封装了at_sendtoTCP 不需指定远端UDP 需要recv vs recvfromat_recv封装了at_recvfromTCP 不需远端信息软件 socket 与硬件 socketAPP 层使用软件 socketAT 命令使用硬件device_socket接收机制信号量阻塞等待 链表取数据核心关键后台线程负责读串口、解析数据包、唤醒对应的 socket六、结尾本篇分析了 RT-Thread 的数据收发机制核心在于后台线程的运作。下一篇将学习后台线程的具体实现。Hello_Embed继续带你从原理到实践掌握嵌入式上位机开发的核心技能敬请关注

更多文章