我刚刚从 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++ 工具集进行编译。
我要去喝啤酒了!
最佳答案
好的,我找到了。这是一个相对微妙的错误。本质上,当编译以下行源代码时;
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。因此,对于未使用的 Socket,WiFiClient::status 返回 true,而不是 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 方法来检查我是否仍然连接,当然,这会导致我每次循环时都会断开连接/重新连接。我们是否有机会让连接返回 true/false ,并在 PuBSubClient::connect 中处理断开连接?
关于arduino - Mosquitto套接字读取错误Arduino客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20339952/