ESP8266-使用本地mDNS地址时HTTPClient不起作用

时间:2018-09-22 18:06:19

标签: http arduino esp8266 arduino-esp8266 mdns

我的本​​地网络服务器具有mDNS-http://android.local:8182 我想通过ESP8266HTTPClient库中的HTTPClient类将其与ESP8266一起使用。代码如下:

HTTPClient http;
http.begin("http://android.local:8182");
http.addHeader("values.json", "text/json");
int code = http.POST(jsonStr);
Log(DATA, "HTTP code: " + String(code));
Log(DATA, "Response: " + http.getString());

但是它总是返回-1代码。当我从字面上复制将URL粘贴到我的PC Web浏览器中时,它可以工作。我尝试用服务器的IP地址替换“ android.local”,并且可以正常工作,但不能使用mDNS地址。有人可以告诉我如何使其正常工作吗?

1 个答案:

答案 0 :(得分:2)

Windows,macOS和Linux均在比ESP8266更强大的计算机上运行。虽然常规DNS和mDNS几乎是相同的协议,但是它们的用法不同,并且分别实现。实际上,如果不安装其他软件(Windows下为“ Bonjour”,Linux下为“ avahi”),Windows和Linux通常不支持mDNS。

您可以通过两种方式使用Arduino SDK在ESP8266上实现此目的。

无论哪种方式,您都需要将android.local解析为其IP地址,然后重写URL以包括IP地址而不是主机名。

不幸的是,ESP8266 mDNS库不支持从主机名到IP地址的直接解析,因此这有点扭曲。

第一种方式:如果正在投放广告android.local的设备为“ http”,“ tcp”提供了mDNS服务记录,并在广告中提供了IP地址和端口号(8182),那么您可以查看使用ESP8266mDNS库更新服务记录。

您的代码应如下所示:

// your other necessary #include's first
#include <ESP8266mDNS.h>

#define HOSTNAME "the name of this ESP8266"
#define TARGET_HOSTNAME "android"

bool resolve_mdns_service(char* service_name, char* protocol, char* desired_host, IPAddress* ip_addr, uint16_t *port_number) {
  Serial.println("Sending mDNS query");
  int n = MDNS.queryService(service_name, protocol);
  Serial.printf("mDNS query got %d results\n", n);

  if(n == 0) {
    Serial.println("no services found");
  } else {
    for (int i = 0; i < n; ++i) {
#ifdef DEBUG
      Serial.print(i + 1);
      Serial.print(": ");
      Serial.print(MDNS.hostname(i));
      Serial.print(" (");
      Serial.print(MDNS.IP(i));
      Serial.print(":");
      Serial.print(MDNS.port(i));
      Serial.println(")");
#endif

      if(strcmp(MDNS.hostname(i).c_str(), desired_host) == 0) {
        *ip_addr = MDNS.IP(i);
        *port_number = MDNS.port(i);
        return true;
      }
    }
  }

  return false;
}

void setup() {
  // get WiFi setup first

  if(!MDNS.begin(HOSTNAME))
    Serial.println("Error setting up MDNS responder!");
  else
    Serial.println("mDNS responder started");

  IPAddress server_ip;
  uint16_t port_number;

  if(resolve_mdns_service("http", "tcp", TARGET_HOSTNAME, &server_ip, &port_number)) {
    Serial.printf("got an answer for %s.local!\n", TARGET_HOSTNAME);
    Serial.println(server_ip);
    Serial.println(port_number);
  } else {
    Serial.printf("Sorry, %s.local not found\n", TARGET_HOSTNAME);
  }
}

仅当您的设备宣传“ http”,“ tcp” mDNS服务记录时,此方法才起作用。

如果没有,最好的办法是使用第三方库。

在这种情况下,您需要按照说明在项目中安装该库:

https://github.com/madpilot/mDNSResolver

您的代码将如下所示:

// your other necessary #include's first
#include <mDNSResolver.h>

#define TARGET_HOSTNAME "android"

WiFiUDP udp;
mDNSResolver::Resolver resolver(udp);

void setup() {
  // get WiFi setup first

  Serial.printf("Attempting to resolve %s\n", TARGET_HOSTNAME);
  IPAddress answer = resolver.search(TARGET_HOSTNAME);
  if(answer == IPADDR_NONE) {
    Serial.println("no answer found");
  } else {
    Serial.println("Gotta result!");
    Serial.println(answer);
  }
}

第一种方法需要更多代码,但不需要外部第3方库,并且在所有情况下都无法使用。

拥有IP地址后,您可以使用它来组合传递给http.begin()的URL,然后从那里继续。

mDNS是一种“不可靠”的协议-它不能保证您将获得答案或所有答案。因此,如果您在第一种方法中定义DEBUG,则每次查看的结果集可能会略有不同。而且,如果您的代码无法解析主机名,则可能要重试2-3次,然后再放弃。