2

我刚刚从 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) {
   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);

现在,上面 Serial.print 的结果原来是 0xFF !!!因此, uint8_t 数组未正确初始化。@knoleary您指向坏FF字节的指针使我想到了这一点。

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

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

有谁知道为什么会这样?

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

我要去喝啤酒!

4

2 回答 2

3

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

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

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

事实证明,Arduino WiFi 代码 WiFi.cpp 中有一个错误。这是代码:

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));
  }
}

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

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

并且 MAX_SOCK_NUM 是 4,而不是 255。因此,WiFiClient::status 返回 true,而不是未使用的 Socket 的 false。

此方法由 MQTT 客户端调用,如下所示:

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

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

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

于 2013-12-22T15:14:10.330 回答
0

将近一年半后,我遇到了同样的问题。删除

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

PubSubClient 的连接方法中的 _client->stop() 正手为我解决了这个问题。但是,我不确定这实际上是一个解决方案还是只是一个非常肮脏的快速破解来定位问题。

你做了什么来解决这个问题 - 你对上述问题的解释很好,但是我无法轻松提取解决方案;-)

于 2015-05-06T13:50:20.343 回答