Android & NodeMCU, 接收服务器响应无法正常工作?

我已经在 Android 上编写了一个应用程序,可以发送简单的请求(使用 Volley),以发送到服务器。服务器在 NodeMCU(ESP8266)微控制器上运行,使用 Lua 编写。问题是,在发送请求后,应用程序并不总是能够打印响应。如果地址为例如“ http://www.google.com”,它会正确地发送请求并接收和显示响应,但如果是下面的代码中的地址-它会正确地发送请求(服务器会有反应),但不会(?)接收响应(不显示响应,显示:“ That didn ' t work!)。你有什么想法,怎样才能修复它并能够打印响应?

Android(负责发送请求的部分):

buttonSynchro.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        // 实例化请求队列。
        String url = "http://192.168.1.12/";

        // 从所提供的 URL 请求字符串响应。
        StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
                new Response.Listener<String>() {
                    @Override
                    public void onResponse(String response) {
                        // 显示响应字符串的前 500 个字符。
                        testTextView.setText("Response is: "+ response.substring(0,500));
                    }
                }, new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                testTextView.setText("That didn't work!");
            }
        });

        // 将请求添加到请求队列中。
        RequestQueue queue = Volley.newRequestQueue(SettingsActivity.this);
        queue.add(stringRequest);
    }
});

NodeMCU, Lua:

station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)
function receive(conn, request)
        print(request)
        print()
        local buf = "";
        buf = buf.."<!doctype html><html>";
        buf = buf.."<h1> ESP8266 Web Server</h1>";
        buf = buf.."</html>";

        conn:send(buf);
        conn:on("sent", function(sck) sck:close() end);
        collectgarbage();

end

function connection(conn)
    conn:on("receive", receive)

end

srv=net.createServer(net.TCP, 30)
srv:listen(80, connection)
点赞
用户2612259
用户2612259

我不是 Lua 专家,但我认为你是在发送响应后注册了你的“sent”回调函数。

我认为你应该将它移动到连接功能中:

station_cfg={}
station_cfg.ssid="Dom"
station_cfg.pwd="lalala"
wifi.sta.config(station_cfg)

function receive(conn, request)
        print(request)
        print()
        local buf = "";
        buf = buf.."<!doctype html><html>";
        buf = buf.."<h1> ESP8266 Web Server</h1>";
        buf = buf.."</html>";
        conn:send(buf);
        collectgarbage();

end

function connection(conn)
    conn:on("receive", receive)
    conn:on("sent", function(sck) sck:close() end);
end

srv=net.createServer(net.TCP, 30)
srv:listen(80, connection)
2018-03-10 16:52:52
用户131929
用户131929

代码由 nPn 编写,在某些用户代理(macOS 上的 Chrome/Firfox/curl/wget)中正常工作,但在其他用户代理中(macOS 和 iOS 上的 Safari、iOS 上的 Firefox Klar)不起作用,很可能是由于缺少 HTTP 标头造成的。

我建议您坚持我们在文档中提供的示例: https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend

srv = net.createServer(net.TCP)

function receiver(sck, data)
  print(data)
  print()

  -- 如果您要通过 HTTP 发送 HTML,则应改用以下内容
  local response = {"HTTP/1.0 200 OK\r\nServer: NodeMCU on ESP8266\r\nContent-Type: text/html\r\n\r\n"}

  response[#response + 1] = "<!doctype html><html>"
  response[#response + 1] = "<h1> ESP8266 Web Server</h1>"
  response[#response + 1] = "</html>"

  -- 发送并从 'response' 表中删除第一个元素
  local function send(localSocket)
    if #response > 0 then
      localSocket:send(table.remove(response, 1))
    else
      localSocket:close()
      response = nil
    end
  end

  -- 一旦发送了第一块数据就再次触发 send() 函数
  sck:on("sent", send)

  send(sck)
end

srv:listen(80, function(conn)
  conn:on("receive", receiver)
end)

此外,您的代码(以及 nPn 的代码)对 WiFi 有一些不应该有的假设。

wifi.sta.config(station_cfg)(带有 auto-connect=true)和 wifi.stat.connect 是 _异步_,因此是非阻塞的 - 许多其他 NodeMCU API 也是如此。因此,您应将上述代码放入函数中,并仅在设备连接到 AP 并获得 IP 后调用它一次。您可以通过为 WiFi 事件监视器注册 STA_GOT_IP 事件的回调来实现这一点。您将在https://nodemcu.readthedocs.io/en/latest/en/upload/#initlua中找到一个非常详细的样例启动序列,该序列监听所有 WiFi 事件。对于初学者,您可能需要对其进行简化,并仅监听 got-IP 事件。

2018-03-10 21:37:23
用户2612259
用户2612259

根据您上面的评论和您发布的 链接 显示的回溯,您的 Android 应用程序在 onResponse() 方法中崩溃,因为您要求的子字符串长度超过了实际字符串长度。

您可以用多种方式修复此问题,但其中一种方法是将结束索引设置为响应长度和 500 之间的最小值(我假设这是您的 TextView 中可以容纳的最大值?)。您可以尝试更改

testTextView.setText("Response is: "+ response.substring(0,500));

testTextView.setText("Response is: "+ response.substring(0, Math.min(response.length(), n)));

或者您认为更合适的其他方法来限制响应的长度,以避免出现IndexOutOfBoundsException。

在这里查看 substring 方法这里

public String substring(int beginIndex, int endIndex)

返回一个新字符串,它是此字符串的子字符串。子字符串从指定的beginIndex开始,一直到索引结尾的endIndex - 1处的字符。因此,子串的长度为endIndex-beginIndex。

示例:

 "hamburger".substring(4, 8) 返回 "urge"
 "smiles".substring(1, 5) 返回 "mile"

参数: beginIndex - 字符串的开始索引(包括在内)。 endIndex - 字符串的结束索引(不包括在内)。 返回:指定的子字符串。抛出: IndexOutOfBoundsException - 如果 beginIndex 为负,或endIndex 大于此 String对象的长度,或beginIndex 大于 endIndex。

2018-03-13 21:56:06