Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
telnet
官方提供的telnet工具的优化
5.00
发布于 2021-11-29 13:06:55 浏览:2614
订阅该版
[tocm] RTT官方提供的网络小工具集(netutils)中提供了telnet工具。 作为一个远程调试工具,telnet还是很实用的。这个工具可以用起来,但吐槽不少,集中在稳定性上。由于telnet接管了finsh,造成出了问题也不易查,着实让人郁闷。 究竟是哪里出了了问题?怎样解决?笔者提供了一种解决思路。 # **现象** 试验环境: 加入telnet工具(此处不做描述,参见官方文档)。方便起见,添加 INIT_APP_EXPORT(telnet_server),上电启动telnet。 添加一个简单线程test1,如下 ```c static void test1(void* parameter) { rt_uint32_t i=0; while(1) { rt_kprintf("test1 cnt: %u\n",i++); rt_thread_delay(70); } } static int start_threads(void) { rt_thread_t tid; tid = rt_thread_create("test1", test1, RT_NULL, 1024, 25, 5); if (tid != RT_NULL) { rt_thread_startup(tid); rt_kprintf("test1 start successfully\n"); } return RT_EOK; } INIT_APP_EXPORT(start_threads); ``` 上电,系统运行正常,测试线程test1运行正常,系统线程情况如下图 ![image.png](https://oss-club.rt-thread.org/uploads/20211129/7c365f5d16ceba2ec90e7282a6606c99.png.webp) 测试一下telnet功能,哎,什么情况? ![image.png](https://oss-club.rt-thread.org/uploads/20211129/8e7ab6195c059e8349d2d33be08fec0c.png) 系统崩掉了!咋崩的? 由于telnet接管了finsh,系统崩掉的时候往往网络也不能工作了,来不及打印错误信息!如何解? #**问题排查** 思路:**串口操作简单,不易出问题,那能不能在telnet开启的情况下,原串口也能输出打印信息?** 着手改造telnet.c。 RTT的Telnet实现是把telnet注册成输入输出设备,然后挂载在finsh上,那么锁定目标函数telnet_write()。 修改如下 ```c static rt_size_t telnet_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size) { const rt_uint8_t *ptr; /*取得原控制台设备(串口),并打开*/ rt_device_t udev = rt_device_find(RT_CONSOLE_DEVICE_NAME); if(udev != RT_NULL) rt_device_open(udev, RT_DEVICE_OFLAG_WRONLY); ptr = (rt_uint8_t*) buffer; rt_mutex_take(telnet->tx_ringbuffer_lock, RT_WAITING_FOREVER); while (size) { if (*ptr == '\n') { rt_ringbuffer_putchar(&telnet->tx_ringbuffer, '\r'); /*同时输出到串口*/ rt_device_write(udev, 0, "\r", 1); } /*同时输出到串口*/ rt_device_write(udev, 0, ptr, 1); if (rt_ringbuffer_putchar(&telnet->tx_ringbuffer, *ptr) == 0) /* overflow */ { /*虽然telnet缓冲已满,但依然把剩余字符输出到串口*/ while (size) { rt_device_write(udev, 0, ptr, 1); ptr++; size--; } break; } ptr++; size--; } rt_mutex_release(telnet->tx_ringbuffer_lock); if(udev != RT_NULL) rt_device_close(udev); /* send data to telnet client */ send_to_client(telnet); return (rt_uint32_t) ptr - (rt_uint32_t) buffer; } ``` 经过上述改造,在telnet已经连接的的情况下,串口依然同时打印控制台信息。下一步排查问题。 重复操作,错误完整的信息打印出来了! ![image.png](https://oss-club.rt-thread.org/uploads/20211129/351f0ecfdc533c67fde6f6dcfeb13eae.png) ![image.png](https://oss-club.rt-thread.org/uploads/20211129/3846295d99b5ed99c6adbd9482089c57.png.webp) **啥🙄?test1栈溢出!加大test1线程栈由1024到2048,切换是没问题了。** ![image.png](https://oss-club.rt-thread.org/uploads/20211129/a55b6c4caf6b9e49a7c6726ed8a77c5f.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20211129/7c2a37fc4ea65e849289a2f3c93fa89a.png.webp) 但是,线程telnet、finsh、tcpip的线程栈占用率上升好理解,**线程test1就这么几行代码,怎么需要这么大的栈空间**🙉!?肯定和telnet有关系,得详细分析分析。 #**分析问题** test1线程没有别的操作,仅有rt_kprintf,那么对应的是控制台挂载的io设备(串口、telnet)的写操作。 关注点聚焦到**telnet_write()函数中的send_to_client()**。那么每次rt_kprintf都调用send_to_client(),即网络发送数据。也就是说只要有rt_kprintf调用的所有线程都会进行网络发送操作,其线程栈空间主要就是在这里增加占用的。 ** 所以,使用当前的telnet工具,只要应用线程有rt_kprintf调用,此线程栈空间需求就会变大(上面的测试,接近1KB的增加),作为一个资源有限的系统,这个telnet工具的实用性大打折扣!** #**解决方案** 思路:**把网络发送数据的操作从telnet_write()中移出,telnet_write()只完成缓冲区的数据填充。** 网络发送移到哪里去? 一种方式是单开一个线程,专门处理send_to_client(),采用事件方式触发。社区有小伙伴这样处理了。 这里提出一个更简单的方案:即不开新线程,在telnet线程中一并处理网络【接收】和【发送】。 网络接收为阻塞式,如何实现一并处理网络收发?这里**利用socket的接收超时参数,在接收超时的间隙,处理网络发送。** - 注释掉write函数中的send_to_client, - 修改telenet线程入口函数,加入超时参数设置 ```c ...... telnet->echo_mode = finsh_get_echo(); /* disable echo mode */ finsh_set_echo(0); /* output RT-Thread version and shell prompt */ #ifdef FINSH_USING_MSH msh_exec("version", strlen("version")); #endif rt_kprintf(FINSH_PROMPT); //配置接收超时 { struct timeval tv; tv.tv_sec = 0; //秒 tv.tv_usec = 100000; //微秒 if(setsockopt(telnet->client_fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv))<0) { rt_kprintf("tln to fail !\n"); } } while (1) { /* try to send all data in tx ringbuffer */ send_to_client(telnet); /* do a rx procedure */ if ((recv_len = recv(telnet->client_fd, recv_buf, RECV_BUF_LEN, 0)) > 0) { process_rx(telnet, recv_buf, recv_len); } else if(recv_len == 0) //若超时recv_len == -1 { /* close connection */ client_close(telnet); break; } } ...... ``` 看看运行效果,telnet前后,test1线程栈占用率由8%只升到到12%。再去掉前面测试用的telnet/串口同时输出的代码,还是8%,即**telnet切换前后,test1线程栈占有率没有明显变化!**键盘输入也没有迟滞感,完美😊! ![image.png](https://oss-club.rt-thread.org/uploads/20211129/bd15d11133c536219e7832716e144744.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20211129/9a47c5b605445d72a7f86c9a86da075e.png.webp) ![image.png](https://oss-club.rt-thread.org/uploads/20211129/0ae68fe8dd7a605177f96c3333443324.png.webp) 恢复test1的线程栈1024,telnet正常运行,就不再截图了。 #其他: - send_option_to_client函数中的send_to_client 也可以不用保留。 - Socket的超时参数需要打开开关SO_RCVTIMEO,RTT的LWIP是默认打开的。 #**总结** 本文提供了查找问题的一种方法:实现了telnet和串口同时输出。 本文提供了针对RTT官方提供的telnet工具的一种简洁优化方案:利用socket接收超时参数实现一个线程内一并处理网络数据收发,降低了调用rt_kprintf()的线程的栈空间需求,提高了本工具的实用性。 行文比较随意,欢迎拍砖。
7
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
fengzi
这家伙很懒,什么也没写!
文章
1
回答
58
被采纳
0
关注TA
发私信
相关文章
1
用telnet组件提示bind socket failed
2
telnet功能开启之后,断开网线则死机
3
【已解决】msh使用telnet方式很容易死机,哪里问题呢?
4
telnet例程运行一段时间后出现异常,系统复位
5
TELNET 添加用户名和密码
6
agile telnet 后续改进交流
7
telnet_server 能打印 msh 提示符,但输入字符后回车没有反应
8
finsh 中使用错误指令会卡死,rt-thread版本为 3.0.3
9
w5500使用telnet问题?
10
v4.10 console 切换后, 只能输出打印, 不能接收指令
推荐文章
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组件
热门标签
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
ota在线升级
UART
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
keil_MDK
rt_mq_消息队列_msg_queue
at_device
ulog
C++_cpp
本月问答贡献
踩姑娘的小蘑菇
7
个答案
3
次被采纳
张世争
8
个答案
2
次被采纳
rv666
5
个答案
2
次被采纳
用户名由3_15位
11
个答案
1
次被采纳
KunYi
6
个答案
1
次被采纳
本月文章贡献
程序员阿伟
5
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
大龄码农
1
篇文章
2
次点赞
ThinkCode
1
篇文章
1
次点赞
Betrayer
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部