Mosquitto 套接字读取错误 Arduino 客户端 [英] Mosquitto socket read error Arduino client

查看:46
本文介绍了Mosquitto 套接字读取错误 Arduino 客户端的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚从 Github 下载了最新的 Arduino 库代码,它损坏了我的 MQTT 客户端程序.我在 Arduino 上使用 PubSubClient 1.91,在 Mac OSX 上使用 Mosquitto 1.1.2 (Build 2013-03-07).(我还在 Windows 7 上针对 Mosquitto 进行了测试,同样的问题.)

提供的 Mosquitto 客户端运行良好,(Mac 到 Windows,Windows 到 Mac)所以 Arduino 端的内容存在一些问题.Wireshark 跟踪显示 Arduino 客户端发送以下数据包:

10:15:ff:ff:4d:51:49:73:64:70:03:02:00:0f:00:07:41:72:64:75:69:6e:6f

Mosquitto 经纪人显示:来自 10.0.0.115 的新连接客户端上的套接字读取错误(空),断开连接.

在我开始浏览 MQTT 规范之前,有人能看出发送的数据包有什么问题吗?它必须与新的 Arduino 库代码有关...

* 更新经过进一步调查,这似乎是 avr-g++ 的代码生成问题,尽管生活经验告诉我事实并非如此.这是 PubSubClient.cpp 中的一段代码

boolean PubSubClient::connect(char *id, char *user, char *pass, char* willTopic, uint8_t willQos, uint8_t willRetain, char* willMessage) {如果(!连接()){整数结果 = 0;如果(域!= NULL){结果 = _client->connect(this->domain, this->port);} 别的 {结果 = _client->connect(this->ip, this->port);}如果(结果){nextMsgId = 1;uint8_t d[9] = { 0x00, 0x06, 'M','Q','I','s','d','p',MQTTPROTOCOLVERSION};//d[0] = 0;//d[1] = 6;Serial.print("d[0]=");Serial.println(d[0],HEX);

现在,上面的 Serial.print 结果是 0xFF !!!因此, uint8_t 数组未正确初始化.@knoleary 您指向错误 FF 字节的指针将我引向了这一点.

如果我现在取消对上面两行的注释,并手动将前 2 个字节初始化为 0 和 6,一切正常,并且我的程序可以与 Mosquitto 愉快地通信.

我查看了生成的代码,但我不是 Atmel 专家.

有人知道为什么会这样吗?

我正在 Eclipse 中使用来自 Arduino 1.05 的 AVR-G++ 工具集进行编译.

我要去喝啤酒!

解决方案

好的,我找到了.这是一个相对微妙的错误.本质上,当编译下面这行源代码时;

 uint8_t d[9] = { 0x00, 0x06, 'M','Q','I','s','d','p',MQTTPROTOCOLVERSION};

这 9 个字节作为常量存储在图像的数据部分.在运行时,一个小循环将 9 个字节复制到数组 (d[]) 通过查看组合汇编器/源代码列表,我可以看到 9 个字节存储在数据部分中的位置,然后定期将它们打印出来,直到我发现是什么覆盖了它们.(有点原始,我知道!)

事实证明 WiFi.cpp 中有一个错误,即 Arduino WiFi 代码.代码如下:

uint8_t WiFiClient::connected() {如果(_sock == 255){返回0;} 别的 {uint8_t s = 状态();return !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 ||s == FIN_WAIT_2 ||s == TIME_WAIT ||s == SYN_SENT ||s== SYN_RCVD ||(s == CLOSE_WAIT));}}

事实证明 _sock 变量实际上是这样初始化的:

WiFiClient::WiFiClient() : _sock(MAX_SOCK_NUM) {}

并且 MAX_SOCK_NUM 是 4,而不是 255.因此,对于未使用的套接字,WiFiClient::status 返回 true,而不是 false.

这个方法被MQTT客户端调用如下:

boolean PubSubClient::connected() {布尔 rc;如果(_client == NULL){rc = 假;} 别的 {rc = (int)_client->connected();if (!rc) _client->stop();}返回 rc;}

而且,由于 _client->connected() 方法错误地返回了 true,因此调用了 _client_stop() 方法.这导致写入不存在的套接字数组元素,因此覆盖了我的字符串数据.

@knolleary,我想知道,您的 PubSubClient::connected() 方法断开连接是否有任何具体原因?我在循环中使用 ::connected 方法来检查我是否仍处于连接状态,当然这会导致我每次循环断开连接/重新连接.我们有没有可能让 connected 返回 true/false ,并在 PuBSubClient::connect 中处理断开连接?

I have just downloaded the latest Arduino Library code from Github, and it's broken my MQTT client program. I'm using PubSubClient 1.91 on Arduino, and Mosquitto 1.1.2 (Build 2013-03-07) on Mac OSX. (I also tested against Mosquitto on Windows 7, same problem.)

The supplied Mosquitto clients work fine, (Mac over to Windows, Windows over to Mac) so it's some problem with what's coming from the Arduino end. A wireshark trace shows the Arduino client sending the following data packet:

10:15:ff:ff:4d:51:49:73:64:70:03:02:00:0f:00:07:41:72:64:75:69:6e:6f

And the Mosquitto broker shows: New connection from 10.0.0.115 Socket read error on client (null), disconnecting.

Before I start to crawl through the MQTT spec, can anyone see anything wrong with the data packet being sent? It's got to be something to do with new Arduino library code...

* Update Upon further investigation, it appears to be a code generation problem with avr-g++, although life experience tells me it will turn out not to be so. Here is a snippet of code from PubSubClient.cpp

boolean PubSubClient::connect(char *id, char *user, char *pass, char* willTopic,     uint8_t willQos, uint8_t willRetain, char* willMessage) {
   if (!connected()) {
      int result = 0;

      if (domain != NULL) {
        result = _client->connect(this->domain, this->port);
      } else {
        result = _client->connect(this->ip, this->port);
      }

      if (result) {
         nextMsgId = 1;
         uint8_t d[9] = { 0x00, 0x06, 'M','Q','I','s','d','p',MQTTPROTOCOLVERSION};
//         d[0] = 0;
//         d[1] = 6;
         Serial.print("d[0]="); Serial.println(d[0],HEX);

Now, the result of the Serial.print just above turns out to be 0xFF !!! So, the uint8_t array is not being initialised correctly. @knoleary Your pointer to the bad FF bytes lead me to this.

If I now uncomment the two lines above, and manually initialise the first 2 bytes to 0 and 6, all works fine, and my program communicates happily with Mosquitto.

I've looked at the generated code, but I'm not an Atmel expert.

Does anyone have any clue why this might be?

I'm compiling using the AVR-G++ toolset from Arduino 1.05, in Eclipse.

I'm going for a beer!

解决方案

OK, I found it. It's a relatively subtle bug. Essentially, when the following line of source code is compiled;

    uint8_t d[9] = { 0x00, 0x06, 'M','Q','I','s','d','p',MQTTPROTOCOLVERSION};

the 9 bytes get stored as a constant in the data section of the image. At runtime, a small loop copies the 9 bytes into the array (d[]) By looking at a combined Assembler / source listing, I could see where in the data section the 9 bytes were stored, and then print them out at regular intervals, until I found what was over-writing them. (A bit primitive, I know!)

It turns out the there's a bug in WiFi.cpp , the Arduino WiFi code. Here's the code:

uint8_t WiFiClient::connected() {

  if (_sock == 255) {
    return 0;
  } else {
    uint8_t s = status();

    return !(s == LISTEN || s == CLOSED || s == FIN_WAIT_1 ||
                    s == FIN_WAIT_2 || s == TIME_WAIT ||
                    s == SYN_SENT || s== SYN_RCVD ||
                    (s == CLOSE_WAIT));
  }
}

It turns out the the _sock variable is actually initialised like this:

WiFiClient::WiFiClient() : _sock(MAX_SOCK_NUM) {
}

and MAX_SOCK_NUM is 4, not 255. So, WiFiClient::status returned true, instead of false for an unused Socket.

This method was called by the MQTT Client like this:

boolean PubSubClient::connected() {
   boolean rc;
   if (_client == NULL ) {
      rc = false;
   } else {
      rc = (int)_client->connected();
      if (!rc) _client->stop();
   }
   return rc;
}

And, since the _client->connected() method erroneously returned true, the _client_stop() method was called. This resulted in a write to a non-existent socket array element, and so overwrote my string data.

@knolleary, I was wondering, is there any specific reason that your PubSubClient::connected() method does a disconnect? I use the ::connected method in a loop, to check that I'm still connected, and, of course it results in my getting a disconnect / reconnect each time round the loop. Any chance we could just make connected return true / false , and handle the disconnect in PuBSubClient::connect?

这篇关于Mosquitto 套接字读取错误 Arduino 客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆