Поддержание TCP-соединения в AsyncTask - PullRequest
0 голосов
/ 13 марта 2012

Я использую AsyncTask для установления TCP-соединения и отправки / получения данных через него.

Мой текущий код выглядит сейчас так:

public class NetworkTask extends AsyncTask<Void, byte[], Boolean> {
    Socket nsocket; //Network Socket
    InputStream nis; //Network Input Stream
    OutputStream nos; //Network Output Stream
    boolean bSocketStarted = false;
    byte[] buffer = new byte[4096];

    @Override
    protected void onPreExecute() {
        Log.i(TAG, "onPreExecute");
    }

    @Override
    protected Boolean doInBackground(Void... params) { //This runs on a different thread
        boolean result = false;
        try {
            // Connect to address
            Log.i(TAG, "doInBackground: Creating socket");
            SocketAddress sockaddr = new InetSocketAddress("google.de", 80);
            nsocket = new Socket();
            nsocket.connect(sockaddr, 5000); //10 second connection timeout
            if (nsocket.isConnected()) {
                bSocketStarted = true;
                nis = nsocket.getInputStream();
                nos = nsocket.getOutputStream();
                Log.i("AsyncTask", "doInBackground: Socket created, streams assigned");
                Log.i("AsyncTask", "doInBackground: Waiting for inital data...");
                int read = nis.read(buffer, 0, 4096); //This is blocking
                while(bSocketStarted) {
                    if (read > 0){
                        byte[] tempdata = new byte[read];
                        System.arraycopy(buffer, 0, tempdata, 0, read);
                        publishProgress(tempdata);
                        Log.i(TAG, "doInBackground: Got some data");
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
            Log.i(TAG, "doInBackground: IOException");
            result = true;
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(TAG, "doInBackground: Exception");
            result = true;
        } finally {
            try {
                nis.close();
                nos.close();
                nsocket.close();
            } catch (IOException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }
            Log.i(TAG, "doInBackground: Finished");
        }
        return result;
    }

    public boolean SendDataToNetwork(final byte[] cmd) { //You run this from the main thread.
        // Wait until socket is open and ready to use
        waitForSocketToConnect();

        if (nsocket.isConnected()) {
            Log.i(TAG, "SendDataToNetwork: Writing received message to socket");
            new Thread(new Runnable() {
                public void run() {
                    try {
                        nos.write(cmd);
                    }
                    catch (Exception e) {
                        e.printStackTrace();
                        Log.i(TAG, "SendDataToNetwork: Message send failed. Caught an exception");
                    }
                }
            }
                    ).start();
            return true;
        }
        else
            Log.i(TAG, "SendDataToNetwork: Cannot send message. Socket is closed");

        return false;
    }

    public boolean waitForSocketToConnect() {
        // immediately return if socket is already open
        if (bSocketStarted)
            return true;

        // Wait until socket is open and ready to use
        int count = 0;
        while (!bSocketStarted && count < 10000) {
            try {
                Thread.sleep(500);
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }
            count += 500;
        }

        return bSocketStarted;
    }

    @Override
    protected void onProgressUpdate(byte[]... values) {
        try {
            if (values.length > 0) {
                Log.i(TAG, "onProgressUpdate: " + values[0].length + " bytes received.");

                String str = new String(buffer, "UTF8");
                Log.i(TAG,str);
                tv.setText(str);
                tv.setMovementMethod(new ScrollingMovementMethod());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } 
        finally {}
    }
    @Override
    protected void onCancelled() {
        Log.i(TAG, "Cancelled.");
    }
    @Override
    protected void onPostExecute(Boolean result) {
        if (result) {
            Log.i(TAG, "onPostExecute: Completed with an Error.");

        } else {
            Log.i(TAG, "onPostExecute: Completed.");
        }
    }
}

Я могу создать экземплярЗадача и звонок SendDataToNetwork из моей деятельности.Однако весь текст, который я передаю в SendDataToNetwork, например, «GET / HTTP / 1.1», постоянно отправляется на сервер.

Как я могу изменить свой код, чтобы поддерживать соединение в doInBackground и ничего не делать, пока я не вызову SendDataToNetwork и после отправки байтов на сервер просто подождите, пока новые данные не будут готовы к отправке?По сути, я хочу запустить AsyncTask, пока я не отменю (= закрою соединение) его.

1 Ответ

3 голосов
/ 13 марта 2012
nsocket.connect(sockaddr, 5000); //10 second connection timeout
if (nsocket.isConnected()) {

Тест бессмысленный. Если бы сокет не был подключен, connect() вызвал бы исключение.

Ваш цикл чтения также в корне неверен, поскольку он не продолжает читать. Существуют стандартные решения о том, как читать поток, например ::1005*.

while ((count = in.read(buffer)) > 0)
{
  out.write(buffer, 0, count);
}

Ваш waitForSocketToConnect() метод на самом деле тоже ничего полезного не делает.

Вам нужно все это переосмыслить.

...