안드로이드 TCP 통신 구현

Server TCP 예제

void callStatusListen()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    ServerSocket call_listen_server = new ServerSocket(PORT);
                    Log.d(TAG, "call status listen... : " + call_listen_server.getInetAddress());

                    client = call_listen_server.accept();   //클라이언트 소켓이 연결될 때까지 기다린다

                    while(isCallAlive)
                    {
                        Log.d(TAG, "Client Socket Accepted!");
                        BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));     //클라이언트 소켓의 InputStream에서 
                                                                                                                    // 데이터를 받아오기 위해 BufferedReader를 선언
                        String message = in.readLine(); //클라이언트 소켓이 연결된 후에 값을 읽을 때까지 대기한다(Block 상태)
                        Log.d(TAG, "received message : " + message);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "server socket error : " + e.toString());
                } finally {
                    Log.d(TAG, "Finally called");
                    try {
                        if(client != null)
                            client.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }
            }
        }).start();
    }

Client TCP 예제

void connectCallStatus()
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    InetAddress serverAddr = InetAddress.getByName(sender_ip);
                    client = new Socket(serverAddr, PORT);
                    Log.d(TAG, "client connection success : " + client.getInetAddress().toString());

                    BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
                    while(isCallAlive)
                    {
                        String msg = in.readLine();
                        Log.d(TAG, "msg From Server : " + msg);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.d(TAG, "client socket error : " + e.toString());
                }
            }
        }).start();

    }

//소켓을 통해 서버로 메시지를 보낸다
    void sendCallStatusMessage(String msg)
    {
        try {
            if(client != null && client.isConnected()) {
                PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(client.getOutputStream())));
                out.println(msg);
                Log.d(TAG, "client message write : " + msg + " to " + client.getInetAddress().toString()) ;
                out.flush();    //Output Stream을 통해 Server에 정상적으로 데이터가
                                //전달되기 위해서는 반드시 flush()를 해주어야 한다
            }

        } catch (IOException e) {
            e.printStackTrace();
            Log.d(TAG, "message write failed : " + e.toString());
        }
    }


TCP Server에서 Client의 데이터를 읽지 못하는 경우

정상적으로 서버가 작동하고 클라이언트에서 데이터를 보내는데 서버에서 데이터를 받지 못하는 경우에는 다음과 같은 경우를 생각해 볼 수 있습니다.

  • Server에 Client 소켓이 연결되지 않은 경우
  • Client에서 Output Stream을 통해 데이터가 정상적으로 전달되지 않은 경우


1.Server에 Client 소켓이 연결되지 않은 경우

 
client = call_listen_server.accept();   //클라이언트 소켓이 연결될 때까지 기다린다
 Log.d(TAG, "client socket accepted!");

이 경우에는 위의 소스처럼 클라이언트 소켓을 accept하는 메서드 다음에 Log를 찍어보면 알 수 있습니다.
accept() 메서드가 클라이언트 소켓이 연결될 때까지 계속 기다리고 있기 때문입니다.
따라서 연결이 되면 Log가 찍히게 됩니다.

정상적으로 연결 되었다면 다음 경우를 살펴볼 필요가 있습니다.


2.Client에서 Output Stream을 통해 데이터가 정상적으로 전달되지 않은 경우

이것을 이해하기 위해서는 Output Stream이 작동하는 방식을 살펴볼 필요가 있습니다.


위의 그림을 보면 Client에서 Server로 데이터를 전송하기 위한 통로가 Output Stream입니다.

Output Stream의 메서드인 write나 println을 통해 데이터를 전송한다고 생각하는데 사실 그 이전에 한 단계가 더 있습니다.

Output Stream은 도착지점인 Server에 바로 데이터를 전해주는 것이 아니라 Buffer라는 창고에 데이터를 쌓아둡니다. 그리고 flush라는 메서드를 통해 창고(Buffer)안에 있던 데이터를 도착지점인 Server에 전송하고 새로운 데이터를 쌓기 위해 창고를 비우게 됩니다.


공식 문서에서도 확인할 수 있듯이, 쌓여있던 데이터들이 전송되어 사라지게 됩니다. 그렇기 때문에 이 flush 메서드를 호출하지 않게 되면 서버에서는 아무런 데이터도 받지 못하게 되는 것입니다.

References

안드로이드 TCP 예제

TCP Server로 Client 데이터가 전송되지 않을 때

Output Stream 정의

Output Stream에서 flush()를 꼭 해줘야 하는 이유

댓글()