记录使用jiejie mqttclient遇到的问题,先吐槽下rtt目前的mqtt组件包,都经不起推敲,umqtt感觉很不错,可惜作者因为一些原因也不维护了。差点就想试着移植esp-idf里面的mqtt组件了。
我使用的jiejie大佬的mqttClient就是论坛的kawai-mqtt(因为kawaii-mqtt很久没更新了,mqttClient也有rtt的兼容层推荐大家去github拉下来添加到项目里)github地址,使用enc28j60用的lwip api就可以正常使用,当使用w5500时因为要用sal接口,mqttclent使用sal接口,当mqtt_content时就会卡死。
mqttClient内部有一个线程结构tcp报文, 接受时使用的recv,但是recv在rtt中默认是阻塞的且不让出cpu资源。
现象就是当content时 mqttClient内部的线程就会阻塞在recv且一直占用cpu资源,而且mqttclient任务优先级默认为5(很高了),低于这个优先级的任务就没法获得cpu资源。
可以通过把mqttclient内部线程优先级设置为低优先级解决,但是当应用复杂时对于mqtt信息的响应速度会降低
翻看rtt文档是发现rtt 有非阻塞接收数据的例子使用的select,根据例子修改了下mqttclient接收数据的接口,platform_net_socket.c里面的接收函数
int platform_net_socket_recv_timeout(int fd, unsigned char *buf, int len, int timeout)
{
int nread;
int nleft = len;
unsigned char *ptr;
ptr = buf;
struct timeval tv = {
timeout / 1000,
(timeout % 1000) * 1000};
if (tv.tv_sec < 0 || (tv.tv_sec == 0 && tv.tv_usec <= 0))
{
tv.tv_sec = 0;
tv.tv_usec = 100;
}
// platform_net_socket_setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char )&tv, sizeof(struct timeval));
// while (nleft > 0)
// {
// nread = platform_net_socket_recv(fd, ptr, nleft, 0);
// if (nread < 0)
// {
// return -1;
// }
// else if (nread == 0)
// {
// break;
// }
// nleft -= nread;
// ptr += nread;
// }
// return len - nleft;
fd_set readset;
/ 清空可读事件描述符列表 /
FD_ZERO(&readset);
/ 将需要监听可读事件的描述符加入列表 /
FD_SET(fd, &readset);
/ 等待设定的网络描述符有事件发生 /
/ 至少有一个文件描述符有指定事件发生再向后运行 /
if (0 == select(fd + 1, &readset, RT_NULL, RT_NULL, &tv))
goto next;
/ 查看 sock 描述符上有没有发生可读事件 */
if (FD_ISSET(fd, &readset))
{
while (nleft > 0)
{
nread = platform_net_socket_recv(fd, ptr, nleft, 0);
if (nread < 0)
return -1;
else if (nread == 0)
break;
nleft -= nread;
ptr += nread;
}
}
next:
return len - nleft;
}
问题解决,但是send函数可能也会遇到这个问题。
我这个小菜鸟准备看看网络编程再回来搞了。
原作者:Ryan_CW
|