我正在构建一个应该与 ESP32 通信的 Android 应用程序。设置如下:
这就是我被困的地方:
我用笔记本电脑加入了 WiFi,并通过 WireShark 观察流量。所有广播消息(以及许多其他内容)都是可见的,但是应用程序从不发送 UDP 数据包。
我非常确定 ESP32 端可以正常工作,每次我通过 python 从笔记本电脑发送 udp 数据包时,它们都会到达 ESP。 我这样设置接入点:
const IPAddress gateWay(192, 168, 1, 1);
const IPAddress localIP(192, 168, 1, 1);
const IPAddress subnet(0, 0, 0, 0);
void setup(){
Serial.begin(115200);
// sdUtils.begin();
imu.begin(FILTER_UPDATE_RATE_HZ);
// configure esp as access point
WiFi.softAP(SSID, PASS);
//WiFi.config(localIP, gateWay, subnet);
WiFi.softAPConfig(localIP, gateWay, subnet);
Serial.println(udp.begin(2255));
}
void loop(){
// initiate connection
while (!client.connected()) {
Serial.println("Initializing connection");
// broadcast IP via UDP broadcast
String ipAddress = WiFi.localIP().toString();
udp.beginPacket(WiFi.broadcastIP().toString().c_str(), 2255);
udp.println(ipAddress);
udp.endPacket();
// parse answer
int packetSize;
unsigned long startTime = millis();
do {
packetSize = udp.parsePacket();
} while (!packetSize && (millis() - startTime) < 5000);
if (packetSize) {
// read answer which is IP adress
char buffer[packetSize];
Serial.println(udp.remoteIP().toString());
udp.read(buffer, packetSize);
String phoneIP = buffer;
Serial.println(phoneIP);
// Establish a TCP connection to the phone
client.connect(phoneIP.c_str(), 8080);
// Send data to the phone
client.println("Hello from the ESP32!");
} else {
Serial.println("Server dindn't answer...");
}
}
}
这就是我尝试在 Android 应用程序中发送 UDP 包的方式:
public class Connectivity {
private final Context context;
private WifiManager wifiManager;
private Handler handler;
private DatagramSocket socket;
public Connectivity(Context context) {
this.context = context;
this.handler = new Handler(Looper.getMainLooper());
try {
wifiManager = (WifiManager) this.context.getSystemService(Context.WIFI_SERVICE);
socket = new DatagramSocket(2255);
socket.setBroadcast(true);
} catch (IOException e) {
Log.e(TAG, "failed to create UDP socket", e);
}
}
public void connectSensor(String ssid, String password) {
// make sure wifi is enabled
if (!wifiManager.isWifiEnabled()) {
wifiManager.setWifiEnabled(true);
}
establishConAfterQ(ssid, password);
}
public void disconnectSensor() {
if (wifiManager.isWifiEnabled()) {
wifiManager.disconnect();
wifiManager.setWifiEnabled(false);
}
}
public void start() {
new Thread(this::receive).start();
}
public void receive() {
while (true) {
byte[] buffer = new byte[128];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
try {
socket.receive(packet);
} catch (IOException e) {
Log.e(TAG, "Failed to receive UDP packet", e);
continue;
}
String message = new String(buffer, 0, packet.getLength());
Log.d(TAG, "Received UDP packet: " + message.replace("\n", "") + " from IP address: " + packet.getAddress().toString() + " at port: " + packet.getPort());
// Send the answer
Log.i(TAG, "Sending Answer");
String answer = "Heureka it works!!";
byte[] data = answer.getBytes();
DatagramPacket response = new DatagramPacket(data, data.length, packet.getAddress(), packet.getPort());
try {
socket.send(response);
} catch (IOException e) {
Log.e(TAG, "Failed to send UDP packet", e);
}
}
}
我连接wifi的函数如下所示:
private void establishConAfterQ(String ssid, String password) {
WifiEnterpriseConfig config = new WifiEnterpriseConfig();
config.enableTrustOnFirstUse(true);
config.setPassword(password);
WifiNetworkSpecifier specifier = new WifiNetworkSpecifier.Builder()
.setSsid(ssid)
.setWpa2Passphrase(password)
.build();
NetworkRequest networkRequest = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.setNetworkSpecifier(specifier)
.build();
ConnectivityManager connectivityManager = (ConnectivityManager) this.context.getSystemService(Context.CONNECTIVITY_SERVICE);
// Register a callback to listen for the connection result
ConnectivityManager.NetworkCallback networkCallback = new ConnectivityManager.NetworkCallback() {
@Override
public void onAvailable(android.net.Network network) {
super.onAvailable(network);
Log.d(TAG, "Connected to WiFi network: " + ssid);
}
@Override
public void onUnavailable() {
super.onUnavailable();
Log.d(TAG, "Failed to connect to WiFi network: " + ssid);
}
};
// Request the network connection
connectivityManager.requestNetwork(networkRequest, networkCallback);
}
奇怪的是,当我断开手机与电脑的连接并手动登录 WiFi 热点时,在短时间内一切都运行良好。但是,此后我无法重现此行为。
我是否缺少连接配置之类的内容,以致无法发送 UDP 命令?我已经在谷歌上进行了相当深入的搜索,但我没有找到任何东西。
更新 我发现我可以从android发送udp包到广播地址(255.255.255.255)或者到托管APP的手机的IP地址。但是,我无法访问除这些 IP 之外的任何 IP(或者至少我没有找到 IP)。那么android中是否内置了隐藏的防火墙?
感谢您的帮助!
android 里好像没有隐藏的防火墙。
我使用广播,但不使用(255.255.255.255)。
只需使用 wifiudp 类对象中的 localIP,并将第 4 个八位字节设置为 255,即仅与当前段相关。