Android & NodeMCU,无法正常接收来自服务器的响应?
Android & NodeMCU, receiving response from server does not work properly?
我在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) {
// Instantiate the RequestQueue.
String url = "http://192.168.1.12/";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
testTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
testTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
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)
我不是 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)
nPn 的代码在某些用户代理(macOS 上的 Chrome/Firfox/curl/wget)中有效,但在其他用户代理中无效(macOS 上的 Safari 和 iOS,iOS 上的 Firefox Klar)。这可能是由于缺少 HTTP headers.
我建议您坚持使用我们在 https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend.
文档中的示例
srv = net.createServer(net.TCP)
function receiver(sck, data)
print(data)
print()
-- if you're sending back HTML over HTTP you'll want something like this instead
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>"
-- sends and removes the first element from the 'response' table
local function send(localSocket)
if #response > 0 then
localSocket:send(table.remove(response, 1))
else
localSocket:close()
response = nil
end
end
-- triggers the send() function again once the first chunk of data was sent
sck:on("sent", send)
send(sck)
end
srv:listen(80, function(conn)
conn:on("receive", receiver)
end)
此外,您的代码(以及 nPn 的代码)假设 WiFi 在不可用的地方可用。
wifi.sta.config(station_cfg)
(with auto-connect=true) and wifi.stat.connect
are asynchronous and thus non-blocking - as are many other NodeMCU APIs. Hence, you should put the above code into a function and only call it once the device is connected to the AP and got an IP. You do that by e.g. registering a callback for the STA_GOT_IP
event with the WiFi event monitor. You'll find a very elaborate example of a boot sequence that listens to all WiFi events at https://nodemcu.readthedocs.io/en/latest/en/upload/#initlua。对于初学者,您可能想要 trim 这个并且只听 got-IP.
根据您上面的评论和您发布的显示回溯的 link,您的 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
的响应的长度
看子串方法here
public String substring(int beginIndex,
int endIndex)
Returns a new string that is a substring of this string. The substring
begins at the specified beginIndex and extends to the character at
index endIndex - 1. Thus the length of the substring is
endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge"
"smiles".substring(1, 5) returns "mile"
Parameters:
beginIndex - the beginning index, inclusive.
endIndex - the ending index, exclusive. Returns:
the specified substring. Throws:
IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or
beginIndex is larger than endIndex.
我在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) {
// Instantiate the RequestQueue.
String url = "http://192.168.1.12/";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
// Display the first 500 characters of the response string.
testTextView.setText("Response is: "+ response.substring(0,500));
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
testTextView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
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)
我不是 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)
nPn 的代码在某些用户代理(macOS 上的 Chrome/Firfox/curl/wget)中有效,但在其他用户代理中无效(macOS 上的 Safari 和 iOS,iOS 上的 Firefox Klar)。这可能是由于缺少 HTTP headers.
我建议您坚持使用我们在 https://nodemcu.readthedocs.io/en/latest/en/modules/net/#netsocketsend.
文档中的示例srv = net.createServer(net.TCP)
function receiver(sck, data)
print(data)
print()
-- if you're sending back HTML over HTTP you'll want something like this instead
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>"
-- sends and removes the first element from the 'response' table
local function send(localSocket)
if #response > 0 then
localSocket:send(table.remove(response, 1))
else
localSocket:close()
response = nil
end
end
-- triggers the send() function again once the first chunk of data was sent
sck:on("sent", send)
send(sck)
end
srv:listen(80, function(conn)
conn:on("receive", receiver)
end)
此外,您的代码(以及 nPn 的代码)假设 WiFi 在不可用的地方可用。
wifi.sta.config(station_cfg)
(with auto-connect=true) and wifi.stat.connect
are asynchronous and thus non-blocking - as are many other NodeMCU APIs. Hence, you should put the above code into a function and only call it once the device is connected to the AP and got an IP. You do that by e.g. registering a callback for the STA_GOT_IP
event with the WiFi event monitor. You'll find a very elaborate example of a boot sequence that listens to all WiFi events at https://nodemcu.readthedocs.io/en/latest/en/upload/#initlua。对于初学者,您可能想要 trim 这个并且只听 got-IP.
根据您上面的评论和您发布的显示回溯的 link,您的 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
的响应的长度看子串方法here
public String substring(int beginIndex, int endIndex)
Returns a new string that is a substring of this string. The substring begins at the specified beginIndex and extends to the character at index endIndex - 1. Thus the length of the substring is endIndex-beginIndex.
Examples:
"hamburger".substring(4, 8) returns "urge" "smiles".substring(1, 5) returns "mile"
Parameters: beginIndex - the beginning index, inclusive. endIndex - the ending index, exclusive. Returns: the specified substring. Throws: IndexOutOfBoundsException - if the beginIndex is negative, or endIndex is larger than the length of this String object, or beginIndex is larger than endIndex.