【发布时间】:2011-08-20 16:41:08
【问题描述】:
我用 Java 编写了一个简单的 TCP 客户端类。它用于连接到用 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 服务器仅将“客户端连接”和“客户端断开连接”打印到标准输出。这在普通 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 仍然阻塞等待输入。像 mReader.close() 这样的调用也在 close-method 块中。
有谁知道如何解决这个问题,以便在 Activity 暂停时成功关闭连接?
【问题讨论】:
-
好的,我想我找到了解决方案 :-) 现在我在关闭方法中调用
mSocket.shutdownInput()和mSocket.shutdownOutput()。这会导致 readLine() 返回并且我的 InputHandler-Thread 退出并且服务器打印“断开连接”消息。 -
您只需要 shutdownInput() 即可。
标签: java android android-activity tcp bufferedreader