套接字未在Android上关闭

时间:2011-05-07 10:10:18

标签: java android android-activity tcp bufferedreader

我在Java中编写了一个简单的TCP-client类。它用于连接到用Python编写的TCP服务器,并在新线程中处理传入的消息。它看起来像这样:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;

public class TCPTestClient {
    private String mHost;
    private int mPort;

    private Socket mSocket;
    private PrintWriter mWriter;
    private BufferedReader mReader;

    public TCPTestClient(String host, int port) {
        mHost = host;
        mPort = port;
    }

    public void connect() throws IOException {
        if (mSocket == null || mSocket.isClosed()) {
            mSocket = new Socket();
            mSocket.connect(new InetSocketAddress(mHost, mPort), 5000);
            mWriter = new PrintWriter(mSocket.getOutputStream());
            mReader = new BufferedReader(new InputStreamReader(mSocket
                    .getInputStream()));
            new Thread(new InputHandler(mReader, this)).start();
        }
    }

    public void close() throws IOException {
        if (mSocket != null && !mSocket.isClosed()) {
            mSocket.close();
        }
    }

    class InputHandler implements Runnable {
        BufferedReader mReader;
        TCPTestClient mClient;

        public InputHandler(BufferedReader reader, TCPTestClient client) {
            mReader = reader;
            mClient = client;
        }

        public void run() {
            String line = null;
            try {
                while ((line = mReader.readLine()) != null) {
                    System.out.println(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

如果新客户端已连接或断开连接,TCP服务器只会将“客户端连接”和“客户端断开连接”打印到stdout。在普通的java应用程序中运行TCPTestClient时,这很有用:连接在调用connect()时建立,在调用close()时关闭,并且InputHandler中的等待readLine()因为SocketException说套接字是关闭(java.net.SocketException: Socket closed)。这是我预期的行为。

但是当我在Android上运行此代码时,连接将不会被关闭:readLine()仍会阻塞而不会抛出SocketException,并且服务器不显示“客户端已断开连接”消息。

这是我的活动:

import java.io.IOException;

import android.app.Activity;
import android.util.Log;

public class Foo extends Activity {
    private TCPTestClient mClient;

    private static final String TAG = "Foo";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.foo);

        mClient = new TCPTestClient("192.168.1.2", 3456);
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.d(TAG, "onPause");

        try {
            mClient.close();
        } catch (IOException e) {
            Log.d(TAG, "Disconnect failed", e);
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.d(TAG, "onResume");

        try {
            mClient.connect();
        } catch (IOException e) {
            Log.d(TAG, "Connect failed", e);
        }
    }
}

因此,当Activity启动/恢复时,将建立连接。当用户点击后退按钮时,应该关闭连接。但是,调用onPause()和close(),但套接字未关闭,因为BufferedReader仍然阻塞等待Input。封闭方法中的mReader.close()之类的调用也会阻止。

是否有人知道如何解决此问题,以便在暂停活动时成功关闭连接?

2 个答案:

答案 0 :(得分:0)

您如何确认客户端套接字未关闭?

在服务器端检测已关闭连接的唯一可靠方法是写入数据,并在协议中添加心跳。

答案 1 :(得分:0)

是的,在2.3之前你必须使用mSocket.shutdownInput()和mSocket.shutdownOutput()来抛出异常。但目前在2.2.2中,它对我不起作用。 :(仍然找到一种抛出异常的方法。