【发布时间】:2017-07-12 15:01:36
【问题描述】:
我需要在 IoT 设备(自定义)和 Android 应用程序之间实现 TCP 通信。 对于 Wifi 设备,我们有一个 Server Socket,而在 Android 中,我有一个 AsyncTask 作为客户端 Socket。设备和智能手机都连接到同一个网络。
这是用于初始化/socket-read 和 socket-write 的 Android Client Socket 代码:
变量:
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();
}
从套接字读取:
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();
}
}
流初始化:
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 应用程序向物联网设备发送一个命令(通过 sendDataToNetwork 方法),后者发回一个“ACK”命令字符串。
问题
问题在于,虽然物联网设备总是收到命令,但智能手机很少收到 ACK。有时我会得到类似“ACKACKACKACK”的东西。通过调试物联网设备,我确信它成功发回了 ACK,所以问题在于 InputStream read() 方法没有立即检索到字符串。
有没有办法立即清空 InputStream 缓冲区,以便我每次发送命令时都从 IoT 设备返回一个“ACK”字符串?
更新
我已经更新了套接字配置,因此不再有缓冲区限制,并且我已经用 readFully 替换了 read() 方法。它大大改善了,但仍然犯了一些错误。例如,2-3 次中的一次没有收到 ack,下一轮我得到 2 个 ack。这可能是物联网设备的计算极限吗?还是有更好的方法的余地?
【问题讨论】:
-
nsocket.setReceiveBufferSize(20);。你为什么要搞乱缓冲区大小? -
如果您只期望一个由三个字符组成的字符串(如 ACK),那么在您的读取函数中使用 3 的读取大小。
-
@greenapps 通过设置 nsocket.setReceiveBufferSize(20);它提高了一点成功率。我尝试使用长度为 3 的 read() 调用,但没有任何改善。
-
让设备只发送更多数据。
-
@greenapps 我试过了,如果你发送更多的 ACK 字符串,它只会改进一点。但仍然不是解决方案,而且您也失去了 sincronism,因此您将不知道该 ACK 何时发送!
标签: android sockets tcp inputstream iot