我需要在物联网设备(自定义)和Android应用之间实现TCP通信。 对于Wifi设备,我们有一个服务器 套接字,而在Android中我有一个AsyncTask作为客户端套接字。设备和智能手机都连接到同一网络。
以下是初始化/套接字读取和套接字写入的Android 客户端 套接字代码:
变量:
static public Socket nsocket; //Network Socket
static public DataInputStream nis; //Network Input Stream
static private OutputStream nos; //Network Output Stream
AsyncTask方法doInBackgroud :
@Override
protected Boolean doInBackground(Void... params) { //This runs on a different thread
boolean result = false;
try {
//Init/Create Socket
SocketInit(IP, PORT);
// Socket Manager
SocketUpdate();
} catch (IOException e) {
e.printStackTrace();
Log.i("AsyncTask", "doInBackground: IOException");
clearCmdInStack();
MainActivity.SocketDisconnectAndNetworkTaskRestart();
result = true;
} catch (Exception e) {
e.printStackTrace();
Log.i("AsyncTask", "doInBackground: Exception");
result = true;
} finally {
try {
SocketDisconnect();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
Log.i("AsyncTask", "doInBackground: Finished");
}
return result;
}
套接字初始化:
public void SocketInit(String ip, int port) throws IOException {
InetAddress addr = InetAddress.getByName(ip);
SocketAddress sockaddr = new InetSocketAddress(addr, port);
nsocket = new Socket();
nsocket.setReuseAddress(false);
nsocket.setTcpNoDelay(true);
nsocket.setKeepAlive(true);
nsocket.setSoTimeout(0);
nsocket.connect(sockaddr, 0);
StartInputStream();
StartOutputStream();
}
从Socket读取:
private void SocketUpdate() throws IOException, ClassNotFoundException {
int read = 0;
// If connected Start read
if (socketSingleton.isSocketConnected()) {
// Print "Connected!" to UI
setPublishType(Publish.CONNECTED);
publishProgress();
if(mConnectingProgressDialog != null)
mConnectingProgressDialog.dismiss(); //End Connecting Progress Dialog Bar
//Set Communications Up
setCommunicationsUp(true);
Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
byte[] buffer = new byte[3];
do{
nis.readFully(buffer, 0, 3);
setPublishType(Publish.READ);
publishProgress(buffer);
}while(!isCancelled());
SocketDisconnect();
}
}
Streams init :
public void StartInputStream() throws IOException{
nis = new DataInputStream(nsocket.getInputStream());
}
public void StartOutputStream() throws IOException{
nos = nsocket.getOutputStream();
}
读写方法:
public int Read(byte[] b, int off, int len) throws IOException{
return nis.read(b, off, len); //This is blocking
}
public void Write(byte b[]) throws IOException {
nos.write(b);
nos.flush();
}
public boolean sendDataToNetwork(final String cmd)
{
if (isSocketConnected())
{
Log.i("AsyncTask", "SendDataToNetwork: Writing message to socket");
new Thread(new Runnable()
{
public void run()
{
try
{
Write(cmd.getBytes());
}
catch (Exception e)
{
e.printStackTrace();
Log.i("AsyncTask", "SendDataToNetwork: Message send failed. Caught an exception");
}
}
}).start();
return true;
}
Log.i("AsyncTask", "SendDataToNetwork: Cannot send message. Socket is closed");
return false;
}
应用程序非常简单,android应用程序向IoT设备发送命令(通过sendDataToNetwork方法),后者发回“ACK”命令字符串。
问题
问题在于,虽然IoT设备始终接收命令,但智能手机很少会收到ACK。有时我得到类似“ACKACKACKACK”的东西。通过调试IoT设备,我确信它成功发送回ACK,因此问题在于InputStream read()方法,它不会立即检索字符串。
有没有办法立即清空InputStream缓冲区,这样每次发送命令时我都会从IoT设备返回一个“ACK”字符串?
更新
我已经更新了套接字配置,因此没有更多的缓冲区限制,我用readFully替换了read()方法。它大大改善了,但仍然犯了一些错误。对于2-3次中的一次没有收到ack,我在下一回合得到2 ack。这可能是物联网设备的计算限制吗?或者是否还有更好的方法?
答案 0 :(得分:1)
问题在于InputStream read()方法,它不会立即清空缓冲区。
我不知道什么'清空缓冲区'这意味着,但DataInputStream.readFully()
被指定为一旦传输了一个字节就返回。
有没有办法立即清空InputStream缓冲区,以便我得到一个" ACK"每次发送命令时从IoT设备返回字符串?
实际问题是您一次只能读取更多而不是一个ACK。还有其他人。
available()
,其字节数组为三个字节。