Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
ESP8266
socket
串口
5
ESP8266 socket通信问题,串口溢出
发布于 2022-07-05 10:55:19 浏览:1352
订阅该版
1、硬件平台:原子精英板 stm32f103zet6+esp8266 开发板作为client,网络调试助手模拟server 学习研究AT SOCKET有一段时间了,之前逛论坛提问解决了一些问题。遇到的问题如下: - 1、at socket关闭不彻底,导致重连server时,socket连接号一直递增。(已解决) - 2、socket连接断开,报错 esp0 device socket(0) wait connect result timeout.(已解决) - 3、AT Client接收数据失败,串口获取数据提示超时,该问题会在程序运行一段时间后出现,还未找到原因? ``` [E/at_client] AT Client receive failed, uart device get data error(-2) [E/at.skt.esp] esp0 device receive size(24) data failed. ``` - 4、程序运行一段时间后, 提示 ``` [W/UART] Warning: There is no enough buffer for saving data, please increase the RT_SERIAL_RB_BUFSZ option. ``` 论坛里关于这个问题的回答是:增大缓存、及时处理串口数据、降低串口波特率(目前AT串口波特率115200) 结合调试记录,当出现这个提示后,串口会一直卡在串口中断里,如下图: ![1.jpg](https://oss-club.rt-thread.org/uploads/20220705/ce98f2ce2cb908bf01baf2f4c5205161.jpg "1.jpg") 针对这个问题,网络调试助手端每隔2秒会下发指令,长度24.目前`RT_SERIAL_RB_BUFSZ`设置为1024 我觉得增大缓存和降低波特率并不能真正彻底解决问题。还是串口数据处理不及时造成,但我没理解这句话(或者说怎样才算是及时把数据取走了), client端使用的select方式接收数据,按照个人理解,recv接收数据,不就是把数据取走了吗?至于把数据拿去做什么应该和接收没什么关系了。请问这里该如何理解呢? 这个问题的出现最终会导致client再也连不上server。 我的client开了三个线程, - A:socket连接状态判断线程 - B:接收线程 - C:发送线程(发送线程里面模拟了心跳) 线程间通信用的event. 代码如下,可否帮忙看下问题出在哪里 ```c static rt_thread_t tid25 = RT_NULL; static rt_thread_t rx_tid25 = RT_NULL; static rt_thread_t tx_tid25 = RT_NULL; static rt_event_t socket_event = RT_NULL; //socket接收线程 #define CLIENT_THREAD_PRIORITY 25 #define CLIENT_THREAD_STACK_SIZE 1024 #define CLIENT_THREAD_TIMESLICE 10 #define TCPCLIENT_CLOSE (1 << 0) //连接关闭 #define TCPCLIENT_TX (1 << 1) //发送 #define TCPCLIENT_PARSE (1 << 2) //解析接收数据 #define TCPCLIENT_RX_EXIT (1 << 3) //退出接收线程 #define TCPCLIENT_TX_EXIT (1 << 4) //退出发送线程 //连接服务器 static int tcp_connect1(void) { struct sockaddr_in server_addr; struct netdev *netdev = RT_NULL; int sock = -1; char svrbuf[16] = "192.168.1.111"; //rt_err_t ret; // 通过名称获取 netdev 网卡对象 */ netdev = netdev_get_by_name("esp0"); if (netdev == RT_NULL) { LOG_E("get network interface device(%s) failed.", "esp0"); } // 设置默认网卡对象 */ netdev_set_default(netdev); // 初始化预连接的服务端地址 */ server_addr.sin_family = AF_AT; server_addr.sin_port = htons(MySysSet.svrPort); //8887 sprintf(svrbuf,"%d.%d.%d.%d",MySysSet.svrIp[0],MySysSet.svrIp[1],MySysSet.svrIp[2],MySysSet.svrIp[3]);//192.168.1.104 server_addr.sin_addr.s_addr = inet_addr(svrbuf); rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero)); RECONNETC: rt_thread_mdelay(500); // 创建一个socket,类型是SOCKET_STREAM,TCP类型 */ if ((sock = socket(AF_AT, SOCK_STREAM, 0)) == -1) { /* 创建socket失败 */ LOG_E("Socket create error!"); goto RECONNETC; } LOG_I("Socket (%d) create success!", sock); // 连接到服务端 */ if (connect(sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1) { // 连接失败 */ LOG_E("Connect server fail!"); closesocket(sock); goto RECONNETC; } LOG_I("Client connect Server success."); return sock; } // 接收线程入口函数 */ static void tcp_rx_thread(void *parameter) { uint16_t calcCRC,recvCRC;//接收的校验码 int maxfdp1; int rc = 0; int ret; fd_set readset; // 获取需要监听的描述符号最大值 */ maxfdp1 = socketfd + 1; while(1) { // 清空可读事件描述符列表 */ FD_ZERO(&readset); // 将需要监听可读事件的描述符加入列表 */ FD_SET(socketfd,&readset); // 获取需要监听的描述符号最大值 */ //maxfdp1 = socketfd+1; // 等待设定的网络描述符有事件发生 */ rc = select(maxfdp1,&readset,0,0,0); // 至少有一个文件描述符有指定事件发生再向后运行 */ if(rc == 0) continue; // 查看 sock 描述符上有没有发生可读事件 */ if (FD_ISSET(socketfd, &readset)) { // 从sock连接中接收最大BUFSZ - 1字节数据 */ rx_len = recv(socketfd, recv_data, BUFSZ - 1, 0); if (rx_len <= 0) { if(!(errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN)) { LOG_E("recv error!"); //关闭socket ret = closesocket(socketfd); if (ret == 0) { LOG_W("rx closed socketfd (%d) success",socketfd); socketfd = -1; } rt_event_send(socket_event, TCPCLIENT_CLOSE); break; } } else { // 有接收到数据,把末端清零 */ recv_data[rx_len] = '\0'; //解析数据,成功后通知发送 rt_event_send(socket_event, TCPCLIENT_TX); } } rt_thread_mdelay(50); } } // 发送线程入口函数 */ static void tcp_tx_thread(void *parameter) { int ret; const char *str = "alive test"; while(1) { if (rt_event_recv(socket_event, TCPCLIENT_TX, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 30000, RT_NULL) == RT_EOK) { ret = send(socketfd, send_data, tx_len, 0); if (ret <= 0) //发送出错 { //发送失败 LOG_E("data send error."); //关闭socket ret = closesocket(socketfd); if (ret == 0) { LOG_W("tx1 closed socketfd (%d) success",socketfd); socketfd = -1; } rt_event_send(socket_event, TCPCLIENT_CLOSE); break; } } else //心跳包 { ret = send(socketfd, str, strlen(str), 0); if (ret <= 0) //发送出错 { //发送失败 LOG_E("keepalive send error."); ret = closesocket(socketfd); if (ret == 0) { LOG_W("tx2 closed socketfd (%d) success",socketfd); socketfd = -1; } rt_event_send(socket_event, TCPCLIENT_CLOSE); break; } } rt_thread_mdelay(40); } } //判断连接状态线程 static void client_connect_state(void *parameter) { //rt_err_t result; RECONNECT: socketfd = tcp_connect1(); if(socketfd != -1 ) { //创建数据发送线程,优先级25 tx_tid25 = rt_thread_create("client_tx", tcp_tx_thread, RT_NULL, CLIENT_THREAD_STACK_SIZE, CLIENT_THREAD_PRIORITY, CLIENT_THREAD_TIMESLICE); // 如果获得线程控制块,启动这个线程 */ if (tx_tid25 != RT_NULL) { LOG_I("create Client_tx_thread success"); rt_thread_startup(tx_tid25); } //创建接收线程,优先级24 rx_tid25 = rt_thread_create("client_rx", tcp_rx_thread, RT_NULL, CLIENT_THREAD_STACK_SIZE, CLIENT_THREAD_PRIORITY-1, CLIENT_THREAD_TIMESLICE); // 如果获得线程控制块,启动这个线程 */ if (rx_tid25 != RT_NULL) { LOG_I("create Client_rx_thread success"); rt_thread_startup(rx_tid25); } } while(1) { if (rt_event_recv(socket_event, TCPCLIENT_CLOSE, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 10000, RT_NULL) == RT_EOK) { //删除线程 if( rt_thread_delete(rx_tid25) == RT_EOK ) LOG_D("client_rx_thread Delete OK"); rt_thread_mdelay(250); goto RECONNECT; } rt_thread_mdelay(50); } } //创建线程 int fnUserClient(void) { // socket_event = rt_event_create("sock_event", RT_IPC_FLAG_FIFO); if (socket_event == RT_NULL) { LOG_E("tcpclient socket event create failed"); } LOG_D("tcpclient socket event create ok"); //创建线程,优先级23 tid25 = rt_thread_create("cli2svr", client_connect_state, RT_NULL, CLIENT_THREAD_STACK_SIZE, CLIENT_THREAD_PRIORITY-2, CLIENT_THREAD_TIMESLICE); // 如果获得线程控制块,启动这个线程 */ if (tid25 != RT_NULL) { rt_thread_startup(tid25); } else { LOG_E("create Client_thread failed"); return -1; } return 0; } ```
查看更多
crystal266
2022-07-05
嵌入式
1.recv 接口是把数据取走,取走后释放了存储接收到的数据的空间。函数执行如下,接收的 URC 函数将数据放到 `recvpkt_list` 中,然后 recv() 函数从 `recvpkt_list` 中取出数据。 ```c #define recv(s, mem, len, flags) sal_recvfrom(s, mem, len, flags, NULL, NULL) // sal_socket/include/socket/sys_socket/sys/socket.h #define recvfrom(s, mem, len, flags, from, fromlen) sal_recvfrom(s, mem, len, flags, from, fromlen) // sal_socket/include/socket/sys_socket/sys/socket.h |-> sal_recvfrom // sal_socket.c |-> SAL_SOCKET_OBJ_GET // sal_socket.c |-> SAL_NETDEV_IS_UP // sal_socket.c |-> SAL_NETDEV_SOCKETOPS_VALID // sal_socket.c |-> pf->skt_ops->recvfrom // sal_socket.c |-> at_recvfrom // at/at_socket/at_socket.c |-> at_get_socket // at/at_socket/at_socket.c |-> at_recvpkt_get(&(sock->recvpkt_list)...) // 从链表中获取数据 at/at_socket/at_socket.c |-> at_recvpkt_node_delete // 从链表中删除数据释放空间 at/at_socket/at_socket.c ``` 2.获取网络的连接状态可以通过读取网络设备的标志位来获取,如下所示。在网络连接时会与 `"link.rt-thread.org"` 的 `8101` 端口进行数据收发测试,进而修改网络设备的连接标志,可以参考文章 [AT组件源码解析](https://club.rt-thread.org/ask/article/6c98fc0273c817a7.html) ```c /** * @brief 获取esp8266的链接状态 * @return 无 * @return 成功返回0,失败返回-1 */ int get_esp8266_link_status(void) { /* "esp8266" 名字来源于设备注册时使用的名字,在文件 packages/at_device-latest/samples/at_sample_esp8266.c 中定义 */ struct at_device * esp8266_dev = at_device_get_by_name(AT_DEVICE_NAMETYPE_NETDEV, "esp0"); if (esp8266_dev == RT_NULL) { LOG_E("func: %s. get esp8266 at device failed", __FUNCTION__); return -1; } if (esp8266_dev->is_init == RT_FALSE) // 是否初始化 { //LOG_E("%s is not init", "esp0"); return -1; } if (netdev_is_up(esp8266_dev->netdev) == 0) // 网络设备不存在 { return -1; } if (netdev_is_internet_up(esp8266_dev->netdev)) // 判断是否联网 { return 0; } else { return -1; } } ```
3
个回答
默认排序
按发布时间排序
werper
2022-11-07
叫我点灯大师
>请教下:2、socket连接断开,报错 esp0 device socket(0) wait connect result timeout.(已解决) 这个问题怎么解决呢?我刚遇到,还没缕清思路
lora200w
2022-11-21
这家伙很懒,什么也没写!
>at socket关闭不彻底,导致重连server时,socket连接号一直递增。(已解决) 能分享一下吗,我也遇到了这个问题,卡住2周了。
撰写答案
登录
注册新账号
关注者
0
被浏览
1.4k
关于作者
Panyh220213
rm -rf/*
提问
19
回答
1
被采纳
0
关注TA
发私信
相关问题
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
利用stm32f427实现usb转串口,电脑端什么也没有识别到
4
finsh 控制台 适配 RS 485请大神指点????
5
uart_sample.c 中,读串口设备时偏移量pos要设置为-1而不是0?
6
【结贴】at_device软件包中对串口接收数据缺少判断导致数据接收异常
7
串口无法接受数据,但可以发送
8
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
9
串口接收使用方式问题
10
雅特力FINSH问题
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
使用百度AI助手辅助编写一个rt-thread下的ONVIF设备发现功能的功能代码
2
RT-Thread 发布 EtherKit开源以太网硬件!
3
rt-thread使用cherryusb实现虚拟串口
4
《C++20 图形界面程序:速度与渲染效率的双重优化秘籍》
5
《原子操作:程序世界里的“最小魔法单位”解析》
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
ulog
C++_cpp
at_device
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
a1012112796
13
个答案
2
次被采纳
张世争
9
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
本月文章贡献
程序员阿伟
8
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部