2011-05-07 4 views
3

자바에서 간단한 TCP 클라이언트 클래스를 작성했습니다. 이것은 파이썬으로 작성된 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에 "연결된 클라이언트"와 "클라이언트 연결을"인쇄합니다. 이것은 정상적인 자바 응용 프로그램에서 TCPTestClient를 실행할 때 훌륭하게 작동합니다. connect()를 호출 할 때 연결이 설정되고 close()를 호출 할 때 연결이 닫히고 InputHandler 내부에서 대기중인 readLine()은 소켓이 마감 (java.net.SocketException: Socket closed). 이것은 내가 예상 한 행동입니다.

그러나 Android에서이 코드를 실행하면 conection이 닫히지 않습니다. readLine()은 SocketException을 throw하지 않고 계속 차단하고 서버는 "클라이언트 연결이 끊김"메시지를 표시하지 않습니다. 활동이 시작될 때

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); 
     } 
    } 
} 

그래서 /, 연결이됩니다 재개 :

여기 내 활동이다. 그리고 사용자가 뒤로 버튼을 클릭하면 연결이 닫혀 야합니다. 그러나 onPause() 및 close()가 호출되지만 BufferedReader가 입력 대기를 여전히 차단하므로 소켓이 닫히지 않습니다. close-method 블록 안에 mReader.close()과 같은 호출도 있습니다.

활동이 일시 중지되었을 때 연결이 성공적으로 닫히도록이 문제를 해결하는 방법을 아는 사람이 있습니까?

+0

을, 나는 내 닫기 -에서 지금은 \t \t \t'mSocket.shutdownInput을 (전화 :-) 솔루션)'와'mSocket.shutdownOutput을()'찾은 것 같아요 방법. 이로 인해 readLine()이 반환되고 InputHandler-Thread가 종료되고 서버는 "disconnected"메시지를 인쇄합니다. – Biggie

+0

그 경우에는 shutdownInput() 만 필요합니다. – EJP

답변

0

어떻게 클라이언트 소켓이 닫히지 않았습니까?

서버 쪽에서 닫힌 연결을 검색하는 유일한 방법은 데이터를 쓰고 프로토콜에 하트 비트를 추가하는 것입니다.

+0

내가 쓴대로 : 서버는 "클라이언트 연결 끊기"메시지를 표준 출력으로 출력합니다. 또한 InputHandler-Thread는 종료되어야하지만 여전히 readLine()에 정지합니다. 어쩌면 스트림 만 제대로 닫히지 않을 수도 있습니다. 그게 내가 원하는 것 :) 나는 InputStream이 닫히면 서버가 이것을보고 예상 된 메시지를 출력한다고 생각한다. 그러나 앞에서 언급했듯이 mReader.close() 블록도 역시 스트림을 닫는 방법을 모릅니다. 편집 : 그리고 "정상적인 자바"로 예상대로 작동;) – Biggie

0

예 2.3 이전에는 mSocket.shutdownInput() 및 mSocket.shutdownOutput()을 사용하여 예외를 throw해야했습니다. 그러나 현재 2.2.2에서, 그것은 나를 위해 작동하지 않습니다. :(아직도 예외를 던질 수있는 방법을 찾는. OK

+0

혹시 이것을 해결 했습니까? 비슷한 문제가 있었고 'Froyo'이하에서 작동하도록하는 방법을 알 수 없었기 때문에 'minSdkVersion'을'9 '로 올려야했습니다. : / –

관련 문제