2

我一直試圖在特定的端口上使用ESP8266 wifi模塊設置服務器。我完成了。ESP8266 wifi服務器到Android客戶端

我想現在就收到來自它的消息。 每當我使用socket.connect()連接時,我能夠在esp8266中檢測到它。但我無法收到任何消息,服務器通過相同的套接字發送。

我試圖獲得在異步使用DataInputStream類while循環中不斷的消息task.Pls讓我知道如果我的做法或代碼是錯誤的!謝謝!

這是我的代碼:

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); 
     } 

    } 

} 

UPDATE(16-12-15)我所做的doInBackground下的以下變化()。原來我使用了DataInputStream,現在我用BufferedReader替換了它。 更改是在while循環部分下進行的,用於不斷檢查套接字輸入流。還添加了ESP8266代碼以供參考。

現在我能夠接收來自ESP8266發送的文本,但它到達後,才通過CIPSEND CMD送3個或4條消息。例如,如果我發送「你好」,「你好」,「喲」,在發送第三個單詞後,我將所有單詞一起收到爲「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 

UPDATE(17-12-15):增加了對參考圖片 我的Arduino的串行窗口顯示AT + CIPSEND命令。 My arduino serial window, showing the AT+CIPSEND commands

PIC手機上運行的應用程式。 from my app running on phone

+1

這將是非常有用的,看到一些對esp8266的代碼。另外,你的Java代碼有哪些錯誤?例外?時間到? – ProgrammerV5

+0

我的logcat沒有收到任何錯誤。最初如果我使用Datainputstream,我沒有收到任何東西。現在,我將它改爲bufferedReader。但是,只有在使用AT + CIPSEND命令從ESP8266發送最少9個字符後才能收到msg。否則,先前發送的短消息就會聚集在一起,就像上面在帖子中提到的Ive。 –

+0

現在我注意到它不是隻有9個字符,它在android中顯示之前要發送的最少字符數不斷變化。今天,這是約14個字符。它與緩衝讀取器的緩衝區大小有什麼關係?我不認爲,問題是與esp8266,因爲,我測試了一個telnet android應用程序。我可以立即收到像「Hi」,「hello」這樣的小字。 –

回答

1

至於此評論:

...它的工作!在我使用cipclose = 0關閉esp端的連接後,我可以立即獲取這些消息,而不考慮它們的長度。但這是唯一的方法嗎?是否有可能使設備和應用程序交談?如何在telnet應用程序中實現這一點,我可以在那裏連續發送數據,直到我關閉連接。

在上層應用程序層,來自TCPIP連接的數據呈現爲Stream。通過定義明確的應用程序協議(如HTTP或telnet)使用此流,可以定義消息交換。在你的情況基本上Android方面不知道接收的數據量。使用緩衝讀取器後,您可以獲得緩衝答案,而不是整個答案。

例如在telnet協議中有控制命令。因此係統繼續工作。

爲了解決你的情況:每封郵件後

  1. 關閉連接。 (這會減慢速度)
  2. 實現基本的應用程序協議。例如:實現一個消息幀:
 
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. 
+0

你是什麼意思的控制命令?你能舉幾個例子嗎? –