Мне нужно реализовать TCP-связь между устройством IoT (обычным) и Android-приложением. Для устройства Wi-Fi у нас есть СерверSocket, в то время как в Android у меня есть AsyncTask в качестве клиентского сокета. И устройство, и смартфон подключены к одной сети.Android TCP Socket InputStrem Intermittent Read or too Slow
Вот Android Clientгнездо код для инициализации/гнездовых чтения и раструба записи:
Переменные:
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;
}
гнездо Initializzation:
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();
}
}
Streams инициализации:
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;
}
Приложение очень простое, андроид приложение посылает команду (с помощью метода sendDataToNetwork) к устройству IoT и последний посылает обратно «ACK» Командная строка.
Проблема
Проблема заключается в том, что в то время как устройство IoT всегда принимает команду, смартфон редко получает ACK обратно. Иногда я получаю что-то вроде «ACKACKACKACK». Отлаживая устройство IoT, я уверен, что он успешно отправляет ACK, поэтому проблема заключается в методе readStream read(), который не сразу извлекает строку.
Можно ли сразу удалить буфер InputStream, чтобы я получал строку «ACK» с устройства IoT каждый раз, когда отправляю команду?
Update
Я обновил сокет конфигурацию, так что нет больше ограничений буфера и я заменил чтение() метода с readFully. Это значительно улучшилось, но все-таки допустило некоторые ошибки. Для istance один из 2-3 раз не получает ack, и я получаю 2 ack на следующий ход. Возможно, это вычислительный предел устройства IoT? Или есть еще преимущество для лучшего подхода?
'nsocket.setReceiveBufferSize (20); '. Почему вы возитесь с размерами буфера? – greenapps
Если вы ожидаете только строку из трех символов, таких как ACK, тогда используйте функцию чтения размером 3 в вашей функции чтения. – greenapps
@greenapps, установив nsocket.setReceiveBufferSize (20); это немного улучшило показатель успеха. Я попытался вызвать read() с длиной 3, но ничего не улучшилось. – Starivore