Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
AT
在特定情况下AT组件可能无法读完数据
发布于 2018-12-29 21:34:26 浏览:1711
订阅该版
在AT组件的 at_recvfrom 函数中有如下代码段 /* socket passively closed, receive function return 0 */ if (sock->state == AT_SOCKET_CLOSED) { result = 0; goto __exit; } else if (sock->state != AT_SOCKET_CONNECT) { LOG_E("received data error, current socket (%d) state (%d) is error.", socket, sock->state); result = -1; goto __exit; } /* receive packet list last transmission of remaining data */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0) { rt_mutex_release(sock->recv_lock); goto __exit; } rt_mutex_release(sock->recv_lock); 中间省略......... while (1) { /* wait the receive semaphore */ if (rt_sem_take(sock->recv_notice, timeout) < 0) { LOG_E("AT socket (%d) receive timeout (%d)!", socket, timeout); result = -1; goto __exit; } else { if (sock->state == AT_SOCKET_CONNECT) { /* get receive buffer to receiver ring buffer */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *) mem, len); rt_mutex_release(sock->recv_lock); if (recv_len > 0) { break; } } else { LOG_D("received data exit, current socket (%d) is closed by remote.", socket); result = 0; goto __exit; } } } 在实际一个项目应用中通讯过程是这样的:客户端与服务器端采样TCP短连接方式,客户端有数据发送时发起TCP连接, 成功后发送数据到服务器端,服务器端对收到的数据进行校验然并给客户端一个应答数据包然后主动关闭TCP连接。 其中客户端发送数据后立即调用select函数等待服务器端的应答包,当服务器端返回应答包后被唤醒,可能是因为客户端 采用单片机处理速度比较慢,所以客户端在select函数返回准备去读取数据时,服务器端已经断开连接了,这时候sock->state 的状态已经变为AT_SOCKET_CLOSED,这样一来客户端就收不到最后服务器端返回的应答包,客户端认为发送失败了导致 不断的重复发送上一包数据,可能有时候客户端又偶尔能收到一次服务器端的应答数据包,发现这个问题后我讲上面的代码稍微调整了一下顺序 变为如下: /* receive packet list last transmission of remaining data */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0) { rt_mutex_release(sock->recv_lock); goto __exit; } rt_mutex_release(sock->recv_lock); /* socket passively closed, receive function return 0 */ if (sock->state == AT_SOCKET_CLOSED) { result = 0; goto __exit; } else if (sock->state != AT_SOCKET_CONNECT) { LOG_E("received data error, current socket (%d) state (%d) is error.", socket, sock->state); result = -1; goto __exit; } 即先看看缓存中有没有数据包如果有就直接读取返回,如果没有再去判断sock的状态,后面的也做了相应的修改,如下 while (1) { /* wait the receive semaphore */ if (rt_sem_take(sock->recv_notice, timeout) < 0) { LOG_E("AT socket (%d) receive timeout (%d)!", socket, timeout); result = -1; goto __exit; } else { /* get receive buffer to receiver ring buffer */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *) mem, len); rt_mutex_release(sock->recv_lock); if (recv_len > 0) { break; } if (sock->state != AT_SOCKET_CONNECT) { LOG_D("received data exit, current socket (%d) is closed by remote.", socket); result = 0; goto __exit; } } } 之后长时间测试再没遇到收不到最后应答包的问题,不知道有没有更好的解决方案
查看更多
4
个回答
默认排序
按发布时间排序
Cheney_Chen
2019-01-02
这家伙很懒,什么也没写!
楼主提出的问题已经在最新的更新中修复,解决方式类似于楼主的解决方式,详细可以查看这个 PR [https://github.com/RT-Thread/rt-thread/pull/2043](https://github.com/RT-Thread/rt-thread/pull/2043)
s2010202069
2019-01-04
这家伙很懒,什么也没写!
>楼主提出的问题已经在最新的更新中修复,解决方式类似于楼主的解决方式,详细可以查看这个 PR https://gith ... --- 看到了,不过新代码只改了第一部分,后面while(1)中还是没改也可能出现上面那种问题啊[table] [tr][td]/* wait the receive semaphore */[/td][/tr] [tr][td][/td][td] if (rt_sem_take(sock->recv_notice, timeout) < 0)[/td][/tr] [tr][td][/td][td] {[/td][/tr] [tr][td][/td][td] LOG_E("AT socket (%d) receive timeout (%d)!", socket, timeout);[/td][/tr] [tr][td][/td][td] errno = EAGAIN;[/td][/tr] [tr][td][/td][td] result = -1;[/td][/tr] [tr][td][/td][td] goto __exit;[/td][/tr] [tr][td][/td][td] }[/td][/tr] [tr][td][/td][td] else[/td][/tr] [tr][td][/td][td] {[/td][/tr] [tr][td][/td][td] if (sock->state == AT_SOCKET_CONNECT)[/td][/tr] [tr][td][/td][td] {[/td][/tr] [tr][td][/td][td] /* get receive buffer to receiver ring buffer */[/td][/tr] [tr][td][/td][td] rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER);[/td][/tr] [tr][td][/td][td] recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *) mem, len);[/td][/tr] [tr][td][/td][td] rt_mutex_release(sock->recv_lock);[/td][/tr] [tr][td][/td][td] if (recv_len > 0)[/td][/tr] [tr][td][/td][td] {[/td][/tr] [tr][td][/td][td] break;[/td][/tr] [tr][td][/td][td] }[/td][/tr] [tr][td][/td][td] }[/td][/tr] [tr][td][/td][td] else[/td][/tr] [tr][td][/td][td] {[/td][/tr] [tr][td][/td][td] LOG_D("received data exit, current socket (%d) is closed by remote.", socket);[/td][/tr] [tr][td][/td][td] result = 0;[/td][/tr] [tr][td][/td][td] goto __exit;[/td][/tr] [tr][td][/td][td] }[/td][/tr] [tr][td][/td][td] }[/td][/tr] [/table]如果对方返回一个数据包后立刻断开TCP连接,这个线程从等待信号量返回,再去判断sock的状态也会是CLOSED,这样是不是还是可能丢数?
Cheney_Chen
2019-01-07
这家伙很懒,什么也没写!
[i=s] 本帖最后由 Cheney_Chen 于 2019-1-7 20:44 编辑 [/i] 返回一个数据包之后,AT 设备接收到数据 URC 会执行 recv 函数,之后才会接收到连接断开的 URC 再执行 closesocket 函数使得 socket 状态置为 AT_SOCKET_CLOSE,所以不管怎样,数据都会进缓冲区。再者 at_recv 函数在循环等待信号量之前,都会读一遍缓冲区中数据,所以应该可以避免这个问题。 ``` /* receive packet list last transmission of remaining data */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); if((recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *)mem, len)) > 0) // 先读取缓冲区的数据 { rt_mutex_release(sock->recv_lock); goto __exit; } rt_mutex_release(sock->recv_lock); ......... while (1) { /* wait the receive semaphore */ if (rt_sem_take(sock->recv_notice, timeout) < 0) { LOG_E("AT socket (%d) receive timeout (%d)!", socket, timeout); errno = EAGAIN; result = -1; goto __exit; } else { if (sock->state == AT_SOCKET_CONNECT) { /* get receive buffer to receiver ring buffer */ rt_mutex_take(sock->recv_lock, RT_WAITING_FOREVER); recv_len = at_recvpkt_get(&(sock->recvpkt_list), (char *) mem, len); //再等待信号量接收数据 rt_mutex_release(sock->recv_lock); if (recv_len > 0) { break; } } else { LOG_D("received data exit, current socket (%d) is closed by remote.", socket); result = 0; goto __exit; } } } ```
s2010202069
2019-01-08
这家伙很懒,什么也没写!
>返回一个数据包之后,AT 设备接收到数据 URC 会执行 recv 函数,之后才会接收到连接断开的 URC 再执行 clos ... --- 如果接收线程在上面代码第16行处等待recv_notice信号量阻塞,此时服务器发送数据过来,AT 设备接收到数据 URC 会执行 recv 函数,接收完成后释放调用AT_SOCKET_EVT_RECV的回调函数释放recv_notice信号量,此时接收线程会被唤醒,正常情况下接收线程会立刻执行读取数据,但是如果接收线程的优先级比较低,此时如果有其他高优先级任务在跑,那么接收线程会被延迟,最坏的情况是这时候服务断开,AT 设备接收到接收到连接断开的 URC 将状态置为AT_SOCKET_CLOSE,之后轮到接收数据线程执行时发现第25行的状态已经不满足了还是会丢数据,当然这种情况比较极端,但是每个人写的用户程序不一样,很可能会发生,如果接收线程的优先级设置得比解析AT设备数据的线程client_parser的优先级高可能就不会发生这种情况了。所以我上面提出一种解决思路是在第25行先判断缓存中是否有数据,如果有数据就先读数据,如果没有数据再去判断状态,因该可以解决问题
撰写答案
登录
注册新账号
关注者
0
被浏览
1.7k
关于作者
s2010202069
这家伙很懒,什么也没写!
提问
4
回答
5
被采纳
0
关注TA
发私信
相关问题
1
rt-thread 2g/3g/4g通信模块的教程有吗?
2
基于AT指令,用esp8266如何连接mqtt?
3
AT组件使用问题
4
官方AT客户端应用笔记的几个小tip
5
RTT的SAL能够判断使用LWIP或者AT?
6
rt_therad AT组件移植不成功(结贴)
7
AT组件在哪个版本的?
8
AT组件 连接 Onenet 连接失败
9
esp8266 AT指令 MQTT连接问题
10
AT组件使用问题之模块主动上报【已解决】
推荐文章
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
GD32F450 片内 flash驱动适配
2
STM32H7R7运行CherryUSB
3
RT-Smart首次线下培训,锁定2024 RT-Thread开发者大会!
4
使用RC522软件包驱动FM1722
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
UART
WIZnet_W5500
ota在线升级
freemodbus
PWM
flash
cubemx
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
中断
编译报错
Debug
SFUD
rt_mq_消息队列_msg_queue
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
a1012112796
10
个答案
1
次被采纳
踩姑娘的小蘑菇
4
个答案
1
次被采纳
红枫
4
个答案
1
次被采纳
张世争
4
个答案
1
次被采纳
Ryan_CW
4
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
YZRD
2
篇文章
5
次点赞
qq1078249029
2
篇文章
2
次点赞
xnosky
2
篇文章
1
次点赞
Woshizhapuren
1
篇文章
5
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部