[java] 자바 소켓 프로그래밍에서의 동기와 비동기 통신 방식

소켓 프로그래밍은 네트워크 응용 프로그램에서 데이터를 주고받기 위한 표준이다. 자바에서는 java.net 패키지에 소켓 프로그래밍을 위한 클래스와 인터페이스를 제공한다. 소켓 프로그래밍에서는 주로 동기(Synchronous)와 비동기(Asynchronous) 두 가지 통신 방식이 사용된다. 이번 글에서는 자바 소켓 프로그래밍에서의 동기와 비동기 통신 방식에 대해 알아보도록 하자.

동기 통신 방식

동기 통신은 클라이언트와 서버 간의 통신이 요청과 응답이 순차적으로 이루어지는 방식이다. 클라이언트가 요청을 보내면 서버는 해당 요청을 받아 처리하고, 처리 결과를 응답으로 돌려준다. 클라이언트는 응답이 돌아올 때까지 대기한다.

자바에서는 동기 통신을 위해 java.net 패키지의 Socket과 ServerSocket 클래스를 사용할 수 있다. 클라이언트는 Socket 클래스를 이용하여 서버에 연결하고, 서버는 ServerSocket 클래스를 이용하여 클라이언트의 연결 요청을 처리한다.

다음은 자바에서 동기 통신을 사용한 클라이언트 코드의 예제이다.

import java.io.*;
import java.net.*;

public class Client {
    public static void main(String[] args) {
        try {
            Socket socket = new Socket("localhost", 8080);
            
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
            
            out.println("Hello, server!");
            String response = in.readLine();
            System.out.println("Server response: " + response);
            
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

위 코드에서 클라이언트는 서버에 연결한 뒤, “Hello, server!”라는 메시지를 보내고, 서버에서 돌아온 응답을 출력한다.

비동기 통신 방식

비동기 통신은 요청과 응답이 동시에 이루어지지 않는다. 클라이언트는 요청을 보낸 뒤, 응답이 돌아올 때까지 기다리지 않고 다른 작업을 수행할 수 있다. 서버는 클라이언트의 요청을 받아 처리한 뒤, 응답을 직접 클라이언트에게 보내주는 방식이다.

자바에서는 비동기 통신을 위해 java.nio 패키지의 소켓 채널을 사용할 수 있다. 소켓 채널은 Selector 클래스를 사용하여 비동기 통신을 구현한다.

다음은 자바에서 비동기 통신을 사용한 클라이언트 코드의 예제이다.

import java.io.*;
import java.net.*;
import java.nio.*;
import java.nio.channels.*;

public class Client {
    public static void main(String[] args) {
        try {
            SocketChannel socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
            socketChannel.connect(new InetSocketAddress("localhost", 8080));
            
            while (!socketChannel.finishConnect()) {
                // 연결 완료 대기
            }
            
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            buffer.put("Hello, server!".getBytes());
            buffer.flip();
            
            while (buffer.hasRemaining()) {
                socketChannel.write(buffer);
            }
            
            buffer.clear();
            socketChannel.read(buffer);
            buffer.flip();
            
            String response = new String(buffer.array()).trim();
            System.out.println("Server response: " + response);
            
            socketChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

위 코드에서 클라이언트는 소켓 채널을 생성한 뒤 비동기로 서버에 연결한다. 연결이 완료되면 “Hello, server!”라는 메시지를 보내고, 서버에서 돌아온 응답을 출력한다.

위에서 소개한 동기와 비동기 통신 방식은 각각 장단점을 가지고 있다. 동기 통신은 간단하고 직관적이지만, 응답이 돌아올 때까지 대기해야 하므로 서버의 응답이 느려질 경우 성능 문제가 발생할 수 있다. 비동기 통신은 응답 대기 시간 동안 다른 작업을 수행할 수 있기 때문에 성능이 향상되지만, 코드의 복잡성이 증가할 수 있다. 상황에 맞게 적절한 통신 방식을 선택하여 개발을 진행해야 한다.

참고 자료