Socket(소켓)

mskimdev·2026년 4월 21일

Java Network

목록 보기
1/2
post-thumbnail

Socket

코드로 두 컴퓨터가 대화할 수 있을까? 소켓(Socket)이 그 창구다. 자바에서는 java.net 패키지로 네트워크 통신을 구현할 수 있다.


소켓이란?

소켓은 네트워크 상에서 두 프로그램이 데이터를 주고받기 위한 연결 끝점이다. 전화기로 비유하면, 소켓은 전화기고 IP 주소와 포트 번호는 전화번호다.

자바에서는 두 가지 소켓을 사용한다.

  • ServerSocket: 서버 측에서 클라이언트의 연결을 기다린다
  • Socket: 클라이언트 측에서 서버에 연결하거나, 연결이 수락된 후 실제 통신에 사용한다


기본 구조

서버와 클라이언트로 역할이 나뉜다.

서버

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

public class Server {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080); // 8080 포트에서 대기
        System.out.println("서버 시작. 연결 대기 중...");

        Socket socket = serverSocket.accept(); // 클라이언트 연결 수락 (블로킹)
        System.out.println("클라이언트 연결됨");

        // 데이터 읽기
        BufferedReader in = new BufferedReader(
            new InputStreamReader(socket.getInputStream())
        );
        String message = in.readLine();
        System.out.println("받은 메시지: " + message);

        socket.close();
        serverSocket.close();
    }
}

클라이언트

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

public class Client {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 8080); // 서버에 연결

        // 데이터 보내기
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
        out.println("안녕하세요, 서버!");

        socket.close();
    }
}

accept()는 클라이언트가 연결될 때까지 그 자리에서 기다린다. 연결이 오면 Socket 객체를 반환하고, 이후 이 소켓을 통해 데이터를 주고받는다.


스트림으로 데이터 주고받기

소켓 통신은 I/O 스트림을 통해 이루어진다. getInputStream()으로 읽고, getOutputStream()으로 쓴다.

Socket socket = new Socket("localhost", 8080);

// 쓰기 스트림
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

// 읽기 스트림
BufferedReader in = new BufferedReader(
    new InputStreamReader(socket.getInputStream())
);

out.println("Hello");          // 서버로 전송
String response = in.readLine(); // 서버 응답 수신
System.out.println(response);

socket.close();

PrintWriter의 두 번째 인자 true는 자동 flush 옵션이다. println() 호출 시 즉시 전송된다.


양방향 채팅 예시

서버가 클라이언트 메시지를 받아서 다시 돌려보내는 에코 서버다.

// 에코 서버
public class EchoServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);
        Socket socket = serverSocket.accept();

        BufferedReader in = new BufferedReader(
            new InputStreamReader(socket.getInputStream())
        );
        PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

        String line;
        while ((line = in.readLine()) != null) {
            System.out.println("받음: " + line);
            out.println("에코: " + line); // 그대로 돌려보냄
        }

        socket.close();
        serverSocket.close();
    }
}

Thread와 함께 쓰는 이유

위 코드는 클라이언트 하나만 처리할 수 있다. accept()는 한 번만 호출되기 때문이다. 여러 클라이언트를 동시에 처리하려면 연결마다 스레드를 만들어야 한다.

public class MultiServer {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8080);

        while (true) {
            Socket socket = serverSocket.accept(); // 연결마다 반복
            new Thread(() -> {
                try {
                    BufferedReader in = new BufferedReader(
                        new InputStreamReader(socket.getInputStream())
                    );
                    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

                    String line;
                    while ((line = in.readLine()) != null) {
                        out.println("에코: " + line);
                    }
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }).start(); // 각 클라이언트를 별도 스레드에서 처리
        }
    }
}


소켓 닫기

소켓을 다 쓰고 닫지 않으면 자원이 낭비된다. try-with-resources를 쓰면 자동으로 닫힌다.

try (Socket socket = new Socket("localhost", 8080);
     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()))) {

    out.println("Hello");
    System.out.println(in.readLine());

} // 블록을 벗어나면 자동으로 close()

마무리

소켓은 네트워크 통신의 가장 기본 단위다. 서버는 ServerSocket으로 기다리고, 클라이언트는 Socket으로 연결한다. 연결 후엔 스트림으로 데이터를 주고받는다. 클라이언트가 여럿이라면 Thread와 함께 써야 한다는 것도 기억해두면 좋다.

profile
<- 개발 공부하는 나

0개의 댓글