JAVA

Socket 통신 - 단 방향(1:1) 통신 서버 측과 클라이언트 측

jiyoon12 2025. 6. 3. 17:14

소켓(Socket)

네트워크 상에서 통신을 가능하게 하는 끝점을 의미합니다. 두 컴퓨터 간의 데이터를 주고받기 위해 사용되는 인터페이스로, 소켓을 통해 네트워크 연결을 설정하고 데이터를 송수신할 수 있습니다. 쉽게 말해, 소켓은 네트워크를 통해 다른 컴퓨터와 대화하는 전화기 같은 역할을 합니다. (소켓은 사실 파일 개념과 같다)

소켓은 물리적인 장치가 아니라 추상적인 개념의 약속입니다. 네트워크 통신을 위해 소프트웨어적으로 정의된 인터페이스로, 컴퓨터 간의 데이터 교환을 가능하게 하는 규칙과 방법을 의미합니다. 이를 통해 네트워크 애플리케이션이 서로 통신할 수 있습니다.

 

 

단방향 통신

  • 한쪽 방향으로만 데이터를  전송하는 방식입니다.

서버 측 기본 코드를 작성하는 이유

  1. 네트워크 통신의 기초 이해
    • 서버는 네트워크 통신의 핵심 역할을 합니다. 서버 측 코드를 작성하면서 다음 과정을 학습합니다.
      • 서버 소켓(ServerSocket) 생성: 네트워크 연결을 기다리는 소켓입니다.
      • 포트 바인딩: 특정 포트 번호에 서버 소켓을 결합하여 클라이언트가 접근할 수 있도록 합니다.
      • 클라이언트 연결 수락: 클라이언트의 연결 요청을 받아들입니다.
  2. 데이터 수신 이해
    • 서버가 클라이언트로부터 데이터를 수신하는 과정을 학습합니다.
      • 입력 스트림(Input Stream): 클라이언트로부터 데이터를 읽어들입니다.
      • 데이터 처리: 수신된 데이터를 출력하거나 처리합니다.
  3. 오류 처리 및 디버깅
    • 네트워크 통신에서 발생할 수 있는 오류를 처리하고 디버깅하는 과정을 학습합니다.
      • 예외 처리(Exception Handling): 네트워크 연결 문제나 포트 충돌 같은 예외를 처리합니다.
      • 디버깅(Debugging): 코드 문제를 파악하고 해결하는 능력을 키웁니다.
  4. 포트 번호 간단 정리
    • 잘 알려진 포트 번호(0~1023): HTTP(80), HTTPS(443) 등 표준 서비스에 사용.
    • 등록된 포트 번호(1024~49151): 특정 애플리케이션에 사용.
    • 동적/사설 포트 번호(49152~65535): 임시로 할당.
    이번 코드에서는 5000번 포트를 사용했으며, 이는 등록된 포트 번호 범위에 속합니다. 포트 번호는 네트워크 통신에서 데이터를 주고받기 위한 주소로, 0~65535까지 총 65,536개가 있습니다.

  • 서버 측  프로그램만들기
package _server_socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 서버측 코드
 * 간단한 네트워크를 통한 서버측 프로그래밍에 필요한 준비물
 * 1. 서버 소켓이 필요하다.
 * 2. IP와 포트 번호가 필요하다(0 ~ 65535 번까지 설정(컴퓨터 마다))
 * 3. 사전 기반 지식 - 잘 알려진 포트 번호 - 주로 시스템 레벨에서 선점 포트 번호(0부터 1023 까지)
 */
public class ServerFile {

    public static void main(String[] args) {

        // 소켓 통신을 하기 위해서 (서버측)
        // 1. 서버 소켓이 필요하다. (서버측에만 가지면 됨)

        // 서버 소켓을 선언합니다.
        ServerSocket serverSocket = null;

        try {
            // 내가 만든 서버 소켓 프로그래밍에 포트 번호 5000번을 할당 한다.
            // 단, 다른 프로그램이 5000번 포트를 선점하고 있다면 에러 발생한다.
            serverSocket = new ServerSocket(5000);
            System.out.println("서버를 시작합니다 포트번호 - 5000");

            // 클라이언트측 연결을 기다립니다.
            // 내부적으로 while 대기 타고 있음(클라이언트가 연결 요청 할 때 까지)
            Socket clientSocket = serverSocket.accept();
            // 클라이언트와 연결이 되면 서로 서버측 Socket이 생성이 되고 클라이언트 Socket 연결 됨
            System.out.println(">>>> 클라이언트가 연결을 하였습니다 <<<<");

            // 클라이언트에서 보낸 데이터를 읽기 위한 입력 스트림이 필요하다.
            InputStream input = clientSocket.getInputStream(); // 바이트 단위로 데이터를 읽을 수 있음
            // 문자 기반의 스트림으로 확장 + 보조 스트림
            BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            // 클라이언트가 보낸 데이터 한줄 기반으로 읽어 보기
            String message = reader.readLine();
            System.out.println("클라이언트가 보낸 메세지 : " + message);


        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 자원 해제 (서버 소켓 닫기)
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (Exception e) {
                    System.out.println("서버 소켓 종료 중 오류 발생");
                    // 추적이 가능하고, 시간 출력 가능 --> 파일 생성해서 로그를 남겨 버림
                    e.printStackTrace();
                }
            }
        }
    } //end of main
}

 

 

 

  • 클라이언트 측 프로그램 만들기
package _client_socket;

import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;

/**
 * 클라이언트 측 코드
 * 준비물
 * 1. 서버측 컴퓨터의 IP 주소와 포트 번호를 알고 있어야 한다.
 * 2. 소켓이 필요하다.(네트워크 통신의 표준 규약을 지켜야 하니깐)
 * 3. 서버측으로 데이터를 전달 하려면 출력 스트림이 필요 하다.
 */
public class ClientFile {

    public static void main(String[] args) {

        // 생성자 - 연결하고자 하는 컴퓨터 IP 주소, 포트번호 필요
        // 만약 내 컴퓨터에 접근 하고 싶다면 localhost 도 사용 가능하다.
        Socket socket = null;
        try {
            new Socket("localhost", 5000);

            // 서버로 데이터를 보내기 위한 준비물이 필요 하다.
            // 출력 스트림이 필요하다 (문자)

            PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
            writer.println("Hello, Server ~~~!!!!");
            writer.flush(); // 물을 내리다

        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    } // end of main
}