【问题标题】:Maintaining a TCP Connection in an AsyncTask在 AsyncTask 中维护 TCP 连接
【发布时间】:2012-03-13 09:38:06
【问题描述】:

我正在使用 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 步)。
  • 这适用于某种类似 telnet 的应用程序,因此您可以发出原始 SMTP 或 HTTP 命令。只要屏幕处于活动状态或用户为此目的按下断开按钮,我就想保持连接。

标签: java android sockets tcp android-asynctask


【解决方案1】:
nsocket.connect(sockaddr, 5000); //10 second connection timeout
if (nsocket.isConnected()) {

测试毫无意义。如果套接字没有连接,connect() 会抛出异常。

您的读取循环也存在根本缺陷,因为它无法继续读取。关于如何读取流有标准的解决方案,例如:

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

您的 waitForSocketToConnect() 方法也没有真正做任何有用的事情。

你需要重新考虑这一切。

【讨论】:

  • 感谢您的回答。根据您的代码更改 while 循环并删除不必要的函数可以解决我的所有问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-26
  • 1970-01-01
  • 2020-08-12
  • 2017-01-09
  • 1970-01-01
相关资源
最近更新 更多