android - ESP8266 wifi 服务器到 Android 客户端

标签 android sockets android-asynctask bufferedinputstream esp8266

我一直在尝试在特定端口上使用 ESP8266 wifi 模块设置服务器。我已经完成了。

我现在想收到它发来的消息。 每当我使用 socket.connect() 连接时,我都能在 esp8266 中检测到它。但我无法接收任何消息,服务器通过同一个套接字发送。

我正在尝试在异步任务中连续使用 while 循环内的 DataInputStream 获取消息。请告诉我我的方法或代码是否错误!谢谢!

这是我的代码:

    package test.espclient;

import java.io.DataInputStream;
//import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;



public class MainActivity extends Activity {

    TextView textResponse;
    EditText editTextAddress, editTextPort;
    Button buttonConnect, buttonClear,buttonDiscon , buttonSendMsg;

    EditText welcomeMsg;

    Socket socket;

    boolean socketStatus = false;

    MyClientTask myClientTask;


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

        editTextAddress = (EditText) findViewById(R.id.address);
        editTextPort = (EditText) findViewById(R.id.port);
        buttonConnect = (Button) findViewById(R.id.connect);
        buttonClear = (Button) findViewById(R.id.clear);
        buttonDiscon = (Button) findViewById(R.id.closeSocket);
        buttonSendMsg = (Button) findViewById(R.id.sendMsg);
        textResponse = (TextView) findViewById(R.id.response);

        welcomeMsg = (EditText)findViewById(R.id.welcomemsg);

        buttonConnect.setOnClickListener(buttonConnectOnClickListener);

        buttonDiscon.setOnClickListener(buttonDisconnectOnCLickListener);

        //buttonSendMsg.setOnClickListener(sendMessage);

        buttonClear.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                textResponse.setText("");
            }
        });
    }

    OnClickListener buttonConnectOnClickListener = new OnClickListener() {

        @Override
        public void onClick(View arg0) {
      if(socketStatus)
          Toast.makeText(MainActivity.this,"Already talking to a Socket!! Disconnect and try again!", Toast.LENGTH_LONG).show();
      else {
          socket = null;
          String address = editTextAddress.getText().toString();
          int port = Integer.parseInt(editTextPort.getText().toString());
          String tMsg = welcomeMsg.getText().toString();

          if (address == null || port == 0)
              Toast.makeText(MainActivity.this, "Please enter valid address/port", Toast.LENGTH_LONG).show();

          else {
                           myClientTask = new MyClientTask(address,port,tMsg);
                          myClientTask.execute();

          } //else when no active socket conn. and credentials are validated.


      } //else when already active socket conn.
        }
    };

    OnClickListener buttonDisconnectOnCLickListener = new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!socketStatus)
                Toast.makeText(MainActivity.this, "SOCKET Already Closed!!", Toast.LENGTH_SHORT).show();
            else {
                try {
                    onDisconnect();
                    if(myClientTask.isCancelled()) {
                        socket.close();
                        Toast.makeText(MainActivity.this, "Socket Closed!", Toast.LENGTH_SHORT).show();
                        socketStatus = false;
                    }
                    else
                    {
                        Toast.makeText(MainActivity.this, "Couldn't Disconnect! Pls try again!", Toast.LENGTH_SHORT).show();
                        socketStatus = true;
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Toast.makeText(MainActivity.this,e.toString(), Toast.LENGTH_SHORT).show();

                }
            }
        }
    };

//    OnClickListener sendMessage = new OnClickListener() {
//        @Override
//        public void onClick(View v) {
//            String msg = welcomeMsg.toString();
//            if(msg.equals(""))
//            {
//                Toast.makeText(MainActivity.this, "Message is empty!!!", Toast.LENGTH_SHORT).show();
//            }
//            else if(!socketStatus)
//            {
//                Toast.makeText(MainActivity.this, "Please Establish Socket Connection first!", Toast.LENGTH_SHORT).show();
//            }
//            else
//            {
//                MyClientTask myClientTask = new MyClientTask(editTextAddress
//                    .getText().toString(), Integer.parseInt(editTextPort
//                    .getText().toString()),
//                    msg);
//            myClientTask.execute();
//
//            }
//
//        }
//    };

    public void onDisconnect()
    {
        myClientTask.cancel(true);
    }

    public class MyClientTask extends AsyncTask<Void, String, Void> {

        String dstAddress;
        int dstPort;
        String response ="";
        String msgToServer;

        MyClientTask(String addr, int port, String msgTo) {
            dstAddress = addr;
            dstPort = port;
            msgToServer = msgTo;
            Log.w("MSG","Entering async task");
        }



        @Override
        protected Void doInBackground(Void... arg0) {


          //  DataOutputStream dataOutputStream = null;
            DataInputStream dataInputStream = null;

            try {
                socket = new Socket(dstAddress, dstPort);
                socketStatus = true;

               // dataOutputStream = new DataOutputStream(socket.getOutputStream());

//                if(msgToServer != null){
//                    dataOutputStream.writeUTF(msgToServer);
//                }
            }
            catch (UnknownHostException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
                response = "UnknownHostException: " + e.toString();
                socketStatus = false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                response = "IOException: " + e.toString();
            }

            Log.w("MSG","Inside while loop for retrieving data");
           while(!isCancelled()){
               try {
                   dataInputStream = new DataInputStream(socket.getInputStream());
                   response = dataInputStream.readUTF();

                   if(!response.isEmpty())
                   {
                       publishProgress(response);
                       Log.w("Data:",response);
                   }

               } catch (IOException e) {
                   e.printStackTrace();
               }
           }


//                if (dataOutputStream != null) {
//                    try {
//                        dataOutputStream.close();
//                    } catch (IOException e) {
//                        // TODO Auto-generated catch block
//                        e.printStackTrace();
//                    }
//                }

                if (dataInputStream != null) {
                    try {
                        dataInputStream.close();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }

            try {
                Log.w("MSG","Stopping async task");
                socket.close();
                socketStatus = false;
            } catch (IOException e) {
                e.printStackTrace();
                socketStatus = true;
            }
            return null;
        }


        @Override
        protected void onProgressUpdate(String... values) {
            super.onProgressUpdate(values);
            textResponse.setText(values[0]);
            Toast.makeText(MainActivity.this,"Server:"+values[0],Toast.LENGTH_LONG).show();
            Log.w("MSG","Updating with msg");
        }

        @Override
        protected void onPostExecute(Void result) {
            Log.w("MSG","On postExecute method..");
            textResponse.setText(response);
            super.onPostExecute(result);
        }

    }

}

更新(16-12-15) 我在 doInBackground() 下进行了以下更改。 本来我使用DataInputStream,现在我用BufferedReader替换它。 更改是在 while 循环部分下进行的,用于不断检查套接字输入流。还添加了ESP8266代码以供引用。

现在我可以接收从 ESP8266 发送的文本,但只有在我通过 CIPSEND cmd 发送 3 或 4 条消息后它才到达。例如如果我发送“hi”,“hello”“yo”,发送第三个单词后,我会收到所有单词作为“hihelloyo” 我不是每条消息一发出就立即收到,而是很晚才收到。 我不确定到底是什么导致了这个问题。可能是缓冲区大小? 如何解决这个问题?

修改代码:

     protected Void doInBackground(Void... arg0) {


          //  DataOutputStream dataOutputStream = null;
          //  DataInputStream dataInputStream = null;

            try {
                socket = new Socket(dstAddress, dstPort);
                socketStatus = true;
               // dataOutputStream = new DataOutputStream(socket.getOutputStream());

//                if(msgToServer != null){
//                    dataOutputStream.writeUTF(msgToServer);
//                }
            }
            catch (UnknownHostException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
                response = "UnknownHostException: " + e.toString();
                socketStatus = false;
            }
            catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
                response = "IOException: " + e.toString();
            }


            Log.w("MSG","Inside while loop for retrieving data");

            while(!isCancelled() && socketStatus) {
                try {
//                  dataInputStream = new DataInputStream(socket.getInputStream());
//                      response = dataInputStream.readUTF();
                    BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                    response = br.readLine();
                    if (!response.isEmpty()) {
                        publishProgress(response);
                        Log.w("Data:", response);
                    }


                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

ESP266代码

    #include <AltSoftSerial.h>
AltSoftSerial ESP8266 ;//(8,9)|Rx,Tx

int LED = 13;

boolean FAIL_8266 = false;

#define BUFFER_SIZE 128
char buffer[BUFFER_SIZE];

String ssid="\"SSID\"";
String pass="\"PASSWORD\"";

void clearESP8266SerialBuffer()
{
  Serial.println("= clearESP8266SerialBuffer() =");
  while (ESP8266.available() > 0) {
    char a = ESP8266.read();
    Serial.write(a);
  }
  Serial.println("==============================");
}



void sendHTTPResponse(int id, String content)
{
  String response;
  response = "HTTP/1.1 200 OK\r\n";
  response += "Content-Type: text/html; charset=UTF-8\r\n"; 
  response += "Content-Length: ";
  response += content.length();
  response += "\r\n";
  response +="Connection: close\r\n\r\n";
  response += content;

  String cmd = "AT+CIPSEND=";
  cmd += id;
  cmd += ",";
  cmd += response.length();

  Serial.println("--- AT+CIPSEND ---");
  sendESP8266Cmdln(cmd, 1000);

  Serial.println("--- data ---");
  sendESP8266Data(response, 1000);
}

boolean waitOKfromESP8266(int timeout)
{
  do{
    Serial.println("wait OK...");
    delay(1000);
    if(ESP8266.find("OK"))
    {
      return true;
    }

  }while((timeout--)>0);
  return false;
}

//Send command to ESP8266, assume OK, no error check
//wait some time and display respond
void sendESP8266Cmdln(String cmd, int waitTime)
{
  ESP8266.println(cmd);
  delay(waitTime);
  clearESP8266SerialBuffer();
}

//Basically same as sendESP8266Cmdln()
//But call ESP8266.print() instead of call ESP8266.println()
void sendESP8266Data(String data, int waitTime)
{
  ESP8266.print(data);
  delay(waitTime);
  clearESP8266SerialBuffer();
}

void adc()
{
  int ldr;

  for(int i=0;i<=3;i++)
  {
    ldr = analogRead(A0); 
    sendESP8266Cmdln("AT+CIPSEND=0,5",1000);
    sendESP8266Cmdln(String(ldr),1000); 
    delay(1000);
  }
}

void setup() 
{
  Serial.begin(9600);
  ESP8266.begin(9600);
  pinMode(LED,OUTPUT);

  do{
  ESP8266.println("AT+RST");
    delay(1000);
    if(ESP8266.find("Ready"))
    {
      Serial.println("Module is ready");
      delay(1000);
      clearESP8266SerialBuffer();

      sendESP8266Cmdln("AT+CWMODE=1",1000);

      //Join Wifi network
      sendESP8266Cmdln("AT+CWJAP="+ssid+","+pass,6500);

      //Get and display my IP
      sendESP8266Cmdln("AT+CIFSR", 1000);  

      //Set multi connections
      sendESP8266Cmdln("AT+CIPMUX=1", 1000);
      //Setup web server on port 80
      sendESP8266Cmdln("AT+CIPSERVER=1,3333",1000);

      Serial.println("Server setup finish");

      FAIL_8266 = false;
    }else{
      Serial.println("Module have no response.");
      delay(500);
      FAIL_8266 = true;
    }
  }while(FAIL_8266);

  digitalWrite(LED, HIGH);
  ESP8266.setTimeout(1000);
}
void loop() {

  // listen for communication from the ESP8266 and then write it to the serial monitor

     if(ESP8266.available()) // check if the esp is sending a message 
  {
    String msg = ESP8266.readString();

    if(msg.substring(0,4)=="Link")
    Serial.println("Client connected!");

    else if(msg.substring(0,6)=="Unlink")
    Serial.println("Client Disconncected!!");


      else if(msg.substring(1,5)=="+IP")
      {
        Serial.println("Client says: "+msg.substring(9,14));
      }

      else
      {
       // Serial.println("Calling ADC.!");
        //adc();

       // Serial.println("Msg:"+msg.charAt(0)+msg.charAt(1)+msg.charAt(2)+msg.charAt(3));
       // Serial.println("Something recieved!: "+msg.substring(1,2));
        Serial.println("MSG:"+msg);  
      }
  } 

    // listen for user input and send it to the ESP8266
    if ( Serial.available() )       {  ESP8266.write( Serial.read() );  }
  }


//Clear and display Serial Buffer for ESP8266

更新(17-12-15):添加图片供引用 我的 arduino 串行窗口显示 AT+CIPSEND 命令。 My arduino serial window, showing the AT+CIPSEND commands

手机上运行的应用程序的图片。 from my app running on phone

最佳答案

关于此评论:

... it worked! I can get the messages immediately irrespective of their lengths, after i close the connection on esp side using cipclose=0. But is this is the only way? Is it possible to make the device and the app talk? How come it is possible in the telnet application, where i can continuously send data till i close connection on one side.?

在上层应用程序层,来自 TCPIP 连接的数据以流的形式呈现。将此流与定义良好的应用程序协议(protocol)(如 HTTP 或 telnet)一起使用,可以定义消息交换。在你的情况下基本上Android端不知道要接收多少数据。使用缓冲阅读器后,您会得到缓冲答案,而不是整体。

例如,在 telnet 协议(protocol)中存在控制命令。这样系统就可以继续工作。

解决您的问题:

  1. 每条消息后关闭连接。 (这会减慢速度)
  2. 实现基本应用协议(protocol)。例如:实现消息框架:
FRAME
1st byte         : length ( this byte gives the length of the payload )
2nd...255th byte : payload ( this is the actual message )

LOGIC
-Sender packs the frame giving length and payload.
-Sender sends the data
...
-Receiver queries for the available bytes. 
-When available bytes are >1 receive only 1 byte say it is 'n'
-'n' is the length of the total frame
-Read 'n' bytes from the stream. if EOF then return what is received.

除此之外,您还可以执行控制命令。 例如,您可能希望接收器关闭连接,以便您的框架可以:

Byte 1 : length
Byte 2 : command (0=nothing, 1=close conn)
Byte 3..n : payload

LOGIC
-When receiver finished receiving and command is 1 then closes the connection. 

关于android - ESP8266 wifi 服务器到 Android 客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34274774/

相关文章:

android - 在 AsyncTask 上调用 execute() 不会调用 doInBackground()

java - android Wolfram alpha 异常下载网址

java - 从android文件系统中选择多个文件

android - Xamarin iOS/安卓 : Detect Lockscreen/home screen click detection or swipe detection

python - 指纹识别远程操作系统 : Python

c++ - ioctl(sock, SIOCETHTOOL, &ifr) 为什么一直返回-1

java - Android App 后台运行 AsyncTask(Facebook 登录)时切换 Activity

android - 如何为 android 即时应用程序设置 package/applicationId?

java - 当辅助消息应用查看消息时关闭默认消息应用的通知

sockets - 无法打开与系统消息总线的连接 : Failed to connect to socket/var/run/dbus/system_bus_socket