i wrote a simple TCP-client class in Java. It is used to connect to a TCP-server written in Python and handle the incoming messages in a new thread. It looks like this:
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();
}
}
}
}
The TCP-server simply prints "client connected" and "client disconnected" to stdout if a new client has connected or disconnected. This works great when running the TCPTestClient in a normal java-application: The connection is established when calling connect() and closed when calling close() and the waiting readLine() inside the InputHandler will fail because of a SocketException saying that the socket was closed (java.net.SocketException: Socket closed
). This is the behaviour i expected.
But when i run this code on Android, the conection will not be closed: readLine() still blocks without throwing a SocketException and the server does not show the "client disconnected"-message.
Here is my activity:
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);
}
}
}
So when the Activity is started/resumed, the connection will be established. And when the user clicks on the Back-Button, the connection should be closed. However, onPause() and close() is called, but the socket is not closed because the BufferedReader开发者_如何学Python still blocks waiting for Input. A call like mReader.close()
inside the close-method blocks, too.
Does anyone know how to fix this issue so that the connection will be closed successfully when the Activity is paused?
How have you verified that the client socket isn't closed?
The only reliable way to detect closed connections on the server side is to write data, and add heartbeats to the protocol.
Yes, pre 2.3 you have to use mSocket.shutdownInput() and mSocket.shutdownOutput() for it to throw the exception. But currently in 2.2.2, it doesn't work for me. :( Still finding a way to throw an exception.
精彩评论