JAVA

자바 네트워크 — 소켓으로 두 프로그램 연결하기(SOCKET)

PANCO_IT
#자바#JAVA#네트워크#소켓#socket

소켓 통신 4단계: 서버 대기, 접속, 주고받기, 닫기

서버가 포트를 열고 기다리면, 클라이언트가 그 주소로 찾아갑니다.

지금까지 만든 프로그램은 전부 내 컴퓨터 안에서만 돌았습니다. 6편에서 파일에 저장하고, 7편에서 여러 일을 동시에 시켰지만, 여전히 혼자였죠. 이제 프로그램 둘을 서로 연결해 봅니다. 채팅 앱도, 게임 서버도, 우리가 매일 쓰는 웹도 바닥에는 오늘 배울 것이 깔려 있습니다.

소켓이 뭔가요?

소켓(Socket)은 두 프로그램이 데이터를 주고받기 위해 연결하는 통로입니다. 전화선의 양쪽 끝에 꽂는 잭이라고 보면 됩니다.

쉽게 — 전화 걸기와 똑같습니다. 전화를 받으려면 상대가 먼저 전화기를 켜 두고 기다려야 하죠. 그게 서버입니다. 내가 번호를 눌러 거는 쪽이 클라이언트고요. 연결되면 그때부터 양쪽이 말을 주고받습니다. 소켓 통신의 순서가 정확히 이 모양입니다.

IP와 포트 — 건물 주소와 방 번호

전화를 걸려면 번호가 필요하듯, 연결하려면 두 가지를 알아야 합니다.

IP 주소는 그 컴퓨터가 어디 있는지 가리키는 주소입니다. 192.168.0.10 같은 형태죠. 같은 컴퓨터 안에서 시험할 때는 localhost 또는 127.0.0.1을 씁니다.

포트(port) 번호는 그 컴퓨터 안에서 어느 프로그램과 이야기할지 정하는 번호입니다. 컴퓨터 한 대에 프로그램이 여럿 돌기 때문에 필요합니다. IP가 건물 주소라면 포트는 그 안의 방 번호입니다.

포트는 0부터 65535까지 있는데, 낮은 번호(0~1023)는 웹(80)이나 보안 웹(443)처럼 이미 정해진 용도가 있습니다. 연습할 때는 겹치지 않게 7000, 8080처럼 큰 번호를 골라 쓰면 됩니다.

기다리는 쪽과 찾아가는 쪽

서버와 클라이언트는 하는 일이 달라서 코드도 다릅니다.

서버와 클라이언트 코드 비교

그림 1. 서버가 먼저 켜져 있어야 클라이언트가 찾아올 수 있습니다.

서버 쪽부터 봅니다.

ServerSocket server = new ServerSocket(7000);   // 7000번 포트를 열고
System.out.println("접속을 기다립니다");

Socket client = server.accept();                // 누가 올 때까지 여기서 멈춤
System.out.println("접속: " + client.getInetAddress());

ServerSocket은 손님을 받을 창구를 여는 것이고, accept()손님이 올 때까지 기다리는 메서드입니다. 누군가 접속하면 그제야 다음 줄로 넘어가면서 그 손님과 이야기할 Socket을 돌려줍니다.

클라이언트 쪽은 더 짧습니다.

Socket server = new Socket("localhost", 7000);  // 이 주소, 이 포트로 접속

한 줄이면 연결됩니다. 다만 상대가 안 켜져 있으면 그 자리에서 오류가 납니다.

주고받기는 6편과 똑같습니다

연결이 되면 그다음은 익숙한 이야기입니다. 스트림으로 읽고 씁니다. 6편에서 파일에 쓰던 방식과 같은 도구를 그대로 씁니다.

// 서버: 메시지 보내기
DataOutputStream out = new DataOutputStream(client.getOutputStream());
out.writeUTF("환영합니다");
out.flush();

// 클라이언트: 메시지 받기
DataInputStream in = new DataInputStream(server.getInputStream());
String msg = in.readUTF();
System.out.println("받은 메시지: " + msg);

writeUTF로 보내면 반대쪽에서 readUTF로 받습니다. 보낸 방법과 받는 방법은 짝이 맞아야 합니다. writeUTF로 보내 놓고 다른 방식으로 읽으면 글자가 깨지거나 멈춥니다.

flush()는 6편에서 본 것과 같습니다. 버퍼에 고여 있는 데이터를 지금 내보내라는 뜻이라, 이걸 빠뜨리면 상대가 계속 기다리는 일이 생깁니다.

스트림 짝 맞추기 실습

네트워크 연결은 프로그램 두 개를 각자 실행해야 해서 브라우저에서는 돌려볼 수 없습니다. 대신 소켓에서 쓰는 것과 똑같은 스트림 API를 메모리 위에서 확인할 수 있습니다. 아래를 돌려 보고, readUTF 대신 readInt로 바꿔 짝이 안 맞으면 어떻게 되는지도 시험해 보세요.

writeUTF와 readUTF 짝 맞추기
import java.io.*;

public class Main {
  public static void main(String[] args) throws IOException {
      // 소켓 대신 메모리를 통로로 사용 (API는 완전히 동일)
      ByteArrayOutputStream pipe = new ByteArrayOutputStream();

      DataOutputStream out = new DataOutputStream(pipe);
      out.writeUTF("환영합니다");        // 서버가 보내는 쪽
      out.writeInt(2026);
      out.flush();

      DataInputStream in = new DataInputStream(
          new ByteArrayInputStream(pipe.toByteArray()));
      System.out.println("문자: " + in.readUTF());   // 보낸 순서대로
      System.out.println("숫자: " + in.readInt());   // 받아야 합니다

      out.close();
      in.close();
  }
}

📱 코드 실행(실습)은 태블릿·PC에서 이용할 수 있어요. 모바일에서는 위 코드를 눈으로 따라가며 확인하세요.

단골 함정 — accept에서 멈춘 것처럼 보입니다

입문자가 가장 많이 당황하는 지점입니다. 서버를 실행했는데 아무 반응이 없고 프로그램이 끝나지도 않습니다.

이건 고장이 아닙니다. accept()손님이 올 때까지 기다리는 중이라 그렇습니다. 이렇게 결과가 올 때까지 멈춰 서는 동작을 블로킹이라고 부릅니다. 클라이언트를 따로 실행하면 그때 진행됩니다.

두 번째 함정은 포트 충돌입니다. 이미 쓰고 있는 포트를 다시 열려고 하면 BindException이 납니다. 앞서 띄운 서버를 안 끄고 다시 실행할 때 흔히 나오는데, 이전 프로그램을 종료하거나 다른 포트 번호를 쓰면 됩니다.

세 번째는 닫지 않는 것입니다. close()를 빠뜨리면 연결과 포트가 계속 물려 있습니다. 파일과 마찬가지로, 다 쓴 통로는 닫아야 합니다.

여러 명을 받으려면 스레드가 필요합니다

여기서 7편이 이어집니다. 위 서버 코드는 손님을 한 명씩만 처리합니다. 한 사람과 이야기하는 동안 다른 사람은 계속 기다려야 하죠.

while (true) {
    Socket client = server.accept();          // 손님 한 명 받고
    new Thread(new Handler(client)).start();  // 그 손님은 새 스레드에 맡김
    // 곧바로 다음 손님을 받으러 돌아옴
}

손님을 받자마자 그 응대를 새 스레드에 넘기고 자신은 바로 다음 손님을 받으러 돌아갑니다. 채팅 서버가 수십 명을 동시에 상대할 수 있는 이유가 이 구조입니다. 7편에서 배운 스레드가 여기서 실제로 쓰이는 셈입니다.

한 장 정리

항목내용
소켓두 프로그램을 잇는 통로
IP어느 컴퓨터인지 (같은 PC는 localhost)
포트그 컴퓨터의 어느 프로그램인지 (연습은 7000·8080)
서버ServerSocket(포트)accept()로 대기
클라이언트new Socket(IP, 포트)로 접속
주고받기스트림 사용, 보낸 방식과 받는 방식을 짝 맞추기
여러 명접속마다 스레드를 붙여 처리

이것만 기억하면 됩니다. 소켓 통신은 전화와 같아서 받는 쪽이 먼저 켜져 있어야 합니다. 서버가 포트를 열고 accept()에서 기다리고, 클라이언트가 IP와 포트로 찾아가면 연결됩니다. 그다음 주고받기는 6편의 스트림 그대로이고, 여러 명을 받으려면 7편의 스레드를 붙입니다.

미니 퀴즈

개념을 제대로 잡았는지 직접 풀어 봅니다. 정답은 눌러야 나옵니다.

미니 퀴즈

OX 2문제 + 4지선다 3문제


포켓코딩(JAVA3) 8편 · 예제 출처: 강사 개인 GitHub 저장소. 다음 편: 채팅 프로그램 — 소켓과 스레드로 실제로 만들어 보기.

PANCO_IT

IT 지식을 정리하는 개발자

관련 글