香港专业教育学院一直试图在特定端口上使用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);
}
}
}
UPDATE(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命令。
手机上运行的应用程序的图片。
最佳答案
关于此评论:
在上层应用层,来自TCPIP连接的数据以流的形式显示。将此流与定义明确的应用程序协议(protocol)(例如HTTP或telnet)结合使用,即可定义消息交换。在您的情况下,基本上Android方面不知道要接收多少数据。使用缓冲的阅读器后,您将得到缓冲的答案,而不是全部。
例如,在telnet协议(protocol)中,有控制命令。这样系统就可以继续工作了。
要解决您的情况:
框架
第一个字节:长度(此字节给出有效载荷的长度)
2nd ... 255th字节:有效负载(这是实际消息)
逻辑
-发送方打包给出长度和有效负载的帧。
-发送方发送数据
...
-接收器查询可用字节。
-当可用字节大于1时,仅接收1个字节,说它是'n'
-'n'是整个帧的长度
-从流中读取“n”个字节。如果EOF,则返回收到的内容。
除此之外,您还可以实现控制命令。
例如,您可能希望接收器关闭连接,以便您的框架可以是:
字节1:长度
字节2:命令(0 =无效,1 =关闭conn)
字节3..n:有效负载
逻辑
-当接收器完成接收并且命令为1时,则关闭连接。
关于android - ESP8266 wifi服务器到android客户端,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34274774/