You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio应用Socket通信向NodeMCU发消息不稳定问题求助

Android Socket向NodeMCU发送消息稳定性问题

我用Android Studio开发的应用向NodeMCU发送消息,代码能运行但稳定性极差,点击发送按钮约10次才能成功一次。已确认NodeMCU端无问题,用C# Socket编程可以即时发送消息。

Android Studio代码(MainActivity.java)

package com.send.client.socket;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void btnSendOnClick(View v) {
        Thread send = new Thread() {
            @Override
            public void run() {
                try {
                    Socket socket = new Socket("192.168.1.1", 4444);
                    PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
                    writer.println("Hellow World");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        };
        send.start();
    }
}

NodeMCU代码(Arduino.ino)

#include <ESP8266WiFi.h>

const char ssid[] = "NodeMCU" ;
const char pass[] = "12345678";
char ch;
String msg;

IPAddress ip(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
WiFiServer server(4444);
WiFiClient client;

void setup()
{
  Serial.begin(9600);

  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, pass);
  delay(100);
  WiFi.softAPConfig(ip, ip, subnet);
  server.begin();
}

void loop()
{
  client = server.available();

  if (client.available() > 0)
  {
    ch = NULL;
    msg = "";

    while (client.available() > 0)
    {
      ch = client.read();
      msg += ch;
    }
    Serial.print(msg);
  }
}

问题分析与修复方案

核心问题

  • Socket资源未释放:Android端创建Socket后未关闭,导致连接池耗尽,后续请求无法建立连接;PrintWriter的自动刷新机制可能未确保数据完全发送。
  • 无连接超时处理:Socket连接时未设置超时,网络波动时会长期阻塞,导致发送失败。
  • NodeMCU连接逻辑缺陷:loop()中每次调用server.available()会覆盖client对象,前一个连接未处理完时会被丢弃。

修复后的Android代码

package com.send.client.socket;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;

public class MainActivity extends AppCompatActivity {

    private static final String DEVICE_IP = "192.168.1.1";
    private static final int DEVICE_PORT = 4444;
    private static final int CONNECT_TIMEOUT = 3000; // 3秒连接超时

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void btnSendOnClick(View v) {
        new Thread(() -> {
            Socket socket = null;
            PrintWriter writer = null;
            try {
                // 手动设置连接超时
                socket = new Socket();
                socket.connect(new java.net.InetSocketAddress(DEVICE_IP, DEVICE_PORT), CONNECT_TIMEOUT);
                
                writer = new PrintWriter(socket.getOutputStream(), true);
                writer.println("Hello World");
                writer.flush(); // 强制刷新输出流,确保数据发送
                
            } catch (SocketTimeoutException e) {
                e.printStackTrace();
                // 可在此添加UI提示:连接超时
            } catch (IOException e) {
                e.printStackTrace();
                // 可在此添加UI提示:发送失败
            } finally {
                // 务必关闭所有资源
                if (writer != null) {
                    writer.close();
                }
                if (socket != null && !socket.isClosed()) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
}

修复后的NodeMCU代码

#include <ESP8266WiFi.h>

const char ssid[] = "NodeMCU" ;
const char pass[] = "12345678";
char ch;
String msg;

IPAddress ip(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
WiFiServer server(4444);

void setup()
{
  Serial.begin(9600);

  WiFi.mode(WIFI_AP);
  WiFi.softAP(ssid, pass);
  delay(100);
  WiFi.softAPConfig(ip, ip, subnet);
  server.begin();
}

void loop()
{
  // 仅在有新客户端连接时获取client对象
  WiFiClient client = server.available();
  if (client) {
    Serial.println("新客户端连接");
    
    // 持续处理该客户端的消息,直到连接断开
    while (client.connected()) {
      if (client.available() > 0) {
        msg = "";
        while (client.available() > 0) {
          ch = client.read();
          msg += ch;
        }
        Serial.print("收到消息:");
        Serial.println(msg);
      }
      delay(10);
    }
    // 客户端断开后关闭连接
    client.stop();
    Serial.println("客户端断开连接");
  }
}

额外优化建议

  • 确保AndroidManifest.xml添加必要权限:
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    
  • Android端可使用线程池管理发送任务,避免频繁创建线程的开销。
  • NodeMCU端可约定消息结尾符(如\n),更精准地判断一条消息的结束,避免数据截断。

内容的提问来源于stack exchange,提问作者Farid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 17:04:53