[Java] 50. 네트워크 - 프로그램(1)

2025. 7. 1. 16:55·Java/IO, Network
네트워크 - 프로그램(1)

네트워크 - 프로그램(1)

#Java/adv2/Network


/네트워크 프로그램1 - 예제 , /네트워크 프로그램1 - 분석

  • Client
    • 소켓(socket)
      • Socket socket = new Socket("localhost", PORT);
      • 서버쪽의 주소, PORT 지정
      • 내부에서 InetAddress를 사용. IP주소를 통해 TCP 접속을 시도한다 (3-way handshake)
      • 연결이 성공적으로 완료되면 Socket 객체를 반환한다.
      • 남는 포트 하나를 로컬 포트로 자동 할당 해줌(클라이언트쪽 포트)
      • Socket 객체를 통해 서버와 통신할 수 있다.
    • 네트워크 스트림
      • 클라이언트-서버간 통신은 Socket이 제공하는 스트림을 사용한다.
      • socket.getInputStream()
      • socket.getOutputStream()
      • 보조 스트림과 같이 사용하면 다루기 편하다.
        • DataInputStream input = new DataInputStream(socket.getInputStream())
        • DataOutputStream output =new DataOutputStream(socket.getOutputStream())
    • 서버에게 문자 보내기
      • output.writeUTF(string);
    • 서버로부터 문자 받기
      • String received = input.readUTF();
      • 문자를 받을 때 까지 블로킹된다.
    • 자원 정리를 꼭 해줘야 한다.
      • input.close(); output.close(); socket.close();
  • Server
    • 서버 소켓 열기(일반 Socket이랑 다름)
      • ServerSocket serverSocket = new ServerSocket(PORT);
      • 서버는 특정 포트를 열어둬야 클라이언트가 그 포트를 지정해서 접속할 수 있다.
      • 지정한 포트를 사용해서 서버 소켓을 생성하면, 클라이언트는 해당 포트로 서버에 연결할 수 있다.
    • 클라이언트 접속 기다리기
      • Socket socket = serverSocket.accept();
      • 접속 과정
        • 서버가 12345 포트로 서버 소켓을 열어둔다.
        • 클라이언트는 이제 12345 포트로 서버에 접속할 수 있다. 클라이언트가 12345 포트에 연결을 시도한다.
        • 이때 OS 계층에서 TCP 3 way handshake가 발생하고, TCP 연결이 완료된다.
        • TCP 연결이 완료되면 서버는 OS backlog queue라는 곳에 클라이언트와 서버의 TCP 연결 정보를 보관한다.
          • 이 연결 정보를 보면 클라이언트의 IP, PORT, 서버의 IP, PORT 정보가 모두 들어있다.
        • serverSocket.accept() 메서드를 호출하면 backlog queue에서 TCP 연결 정보를 조회하여, Socket 객체를 만들어서 반환한다.
          • 먄약 TCP 연결 정보가 없다면, 연결 정보가 생성될 때 까지 대기한다. (블로킹)
        • 사용한 TCP 연결 정보는 backlog queue에서 제거된다.
    • 서버 입장에서는 리스닝포트가 localport가 되고, 클라이언트가 사용한 임시 포트가 port가 된다.
    • 그 외의 사용법은 Client와 동일한 구조
      • 자원 정리할 때 input, output, socket을 닫고 마지막에 serverSocket도 닫아줘야 한다.
  • 발생할 수 있는 예외
    • 서버를 시작하지 않고 클라이언트를 실행하면 java.net.ConnectException: Connection refused
    • 포트를 다른 프로세스가 사용하고 있다면 java.net.BindException: Address already in use
  • /DNS 탐색
    • InetAddress localhost = InetAddress.getByName("localhost");
    • InetAddress 클래스를 사용하면 호스트 이름으로 대상 IP를 찾을 수 있다.
      1. 자바는 InetAddress.getByName("호스트명") 메서드를 사용해서 해당하는 IP 주소를 조회합니다.
      2. 이 과정에서 시스템의 호스트 파일을 먼저 확인한다.
        • /etc/hosts (리눅스, mac)
        • C:\Windows\System32\drivers\etc\hosts (윈도우,Windows)
      3. 호스트 파일에 정의되어 있지 않다면, DNS 서버에 요청해서 IP 주소를 얻는다.
  • 1번 예제의 문제점
    • 메시지를 하나만 주고 받으면 클라이언트와 서버가 모두 종료된다.

/네트워크 프로그램2 - 예제 , /네트워크 프로그램2 - 분석

  • 클라이언트가 “exit”을 보내야만 클라이언트와 서버가 종료되도록 개선
  • 클라이언트와 서버가 메시지를 주고 받는 부분만 while 로 반복
  • 문제점: 서버는 하나의 클라이언트가 아니라, 여러 클라이언트의 연결을 처리할 수 있어야 한다.
    • 새로 연결한 ClientV2-2 는 소켓 연결은 되지만, 메시지를 전송해도 서버로 부터 아무런 응답이 오지 않는다.
    • 새로 연결한 클라이언트도 3-way ~~ 거치고 OS backlog queue에 담겨서 서버와 TCP 연결은 되었다.
    • 다만 클라이언트에만 socket 객체가 생성되고, 아직 서버에 새로 접속한 쪽의 Socket 객체가 생성되지 않은 것이다.
    • 이 상태에서 클라이언트는 서버에 메시지를 보낼 수는 있다.
      • 클라이언트
        • 애플리케이션 OS TCP 송신 버퍼 → 클라이언트 네트워크 카드
      • 클라이언트가 보낸 메시지가 서버에 도착했을 때, 서버
        • 서버 네트워크 카드 OS TCP 수신 버퍼 → 애플리케이션
      • 서버 애플리케이션에서 아직 읽지 않았기 때문에, 서버 OS의 TCP 수신 버퍼에서 대기하게 된다. OS에 있는 소켓에서 메시지를 inputstream으로 빨아 당겨야 처리할 수 있는 것이다.
    • 여기서 핵심적인 내용이 있는데, 소켓 객체 없이 서버 소켓만으로도 TCP 연결은 완료된다는 점이다.
      • 여기서 핵심적인 내용이 있는데, 소켓 객체 없이 서버 소켓만으로도 TCP 연결은 완료된다는 점이다.
    • V2 구조에서는 새로운 클라이언트가 접속했을 때 서버의 main 스레드는 accept() 메서드를 절대로 호출할 수 없다.
      • 2개의 블로킹 작업: 별도의 스레드로 처리해야 한다.
        • accept() : 클라이언트와 서버의 연결을 처리하기 위해 대기
        • readXxx() : 클라이언트의 메시지를 받아서 처리하기 위해 대기
        • 각각의 블로킹 작업은 별도의 스레드에서 처리해야 한다. 그렇지 않으면 다른 블로킹 메서드 때문에 계속 대기할 수 있다.

/네트워크 프로그램3: 여러 클라이언트가 동시에 접속할 수 있는 서버로 개선

  • 서버의 main 스레드는 서버 소켓을 생성하고, 서버 소켓의 accept() 를 반복해서 호출해야 함
    • 새로운 연결이 있을 때 마다 Socket을 반환한다.
    • 반환된 Socket를 기반으로 Runnable 을 구현한 Session 이라는 별도의 객체를 만들고, 새로운 스레드에서 이 객체를 실행한다.
    • Session 을 담당하는 스레드는 자신의 소켓이 연결된 클라이언트와 메시지를 반복해서 주고 받는 역할을 담당한다.
  • Session
    • Runnable 구현, 별도의 스레드에서 실행됨
    • private final Socket socket;
      • socket에서 스트림 가져와서 통신하고, 종료 시 input, output, socket을 닫아준다.
  • Server
    • serverSocket.accept();를 while문 안에 넣자.
    • socket이 반환되면 새로운 세션과, 스레드를 만들고 thread.start() 호출
  • 문제점
    • 클라이언트의 연결을 직접 종료하면 클라이언트 프로세스가 종료되면서, 클라이언트와 서버의 TCP 연결도 함께 종료된다. 이때 서버에서 readUTF() 로 클라이언트가 메시지를 읽으려고 하면 EOFException 이 발생한다.
    • close() 하는 코드가 try문 안에 있어, EOFException 발생시 catch문으로 점프를 뛰어 자원을 닫지 못하게 된다.
    • 자바 외부의 자원은 자동으로 GC가 되는게 아니므로 꼭 정리를 해줘야 한다.

/자원 정리1

  • 리소스 호출 등에서 발생하는 예외를 위한 CallException, 리소스를 닫는 중 발생하는 예외를 위한 CloseException
    • 리소스의 callEx() 호출 시 CallException 발생, 리소스의 closeEx() 호출 시 CloseException 발생
    • resource1, resource2가 있다고 해보자.
  • resource1.call(); resource2.callEx(); resource2.closeEx(); resource1.closeEx();
    • resource2.callEx() 를 호출하면서 예외가 발생했다. 예외 때문에 자원 정리 코드가 정상 호출되지 않았다.

/자원 정리2 : 예외가 발생해도 자원이 정리되도록 개선

  • resource1과 resource2의 scope를 위해 try 밖에서 선언하고, finally에서 close를 해주자.
  • 자원을 생성하다가 예외가 발생할 수도 있다. close 전에 if문으로 null이 아닌 경우에만 닫아주자.
  • 문제점: resource2.closeEx() resource1.closeEx()를 호출하는 과정
    • resource1의 자원을 닫지 못함 (다른 자원을 닫을 수 없는 문제 발생)
    • 더 큰 문제는, callEx()에서 예외가 터지고, closeEx()에서 또 예외가 터지면서, CloseException을 새로 던지게 된다. 이 때, callException 가 아닌 closeException만 던져진다. callException이 사라져버림
      • 핵심 예외가 바뀌는 문제가 발생한 것이다. 핵심 예외가 사라져버림. 자원을 닫는 건 핵심 예외가 아님.

/자원 정리3 : 자원 정리중에 발생하는 예외를 처리

  • finally 내에서 closeEx()를 try - catch로 한 번 더 예외처리를 해준다.
    • closeEx()에서 발생한 예외는 버림으로써, CallException을 살릴 수 있다.
    • 자원 정리 시점에 발생한 예외는 당장 더 처리할 수 있는 부분이 없으므로, 로그만 남겨서 개발자가 인지하도록 해주자.
  • 아쉬운 부분
    • resource 변수를 선언하면서 동시에 할당할 수 없음(try , finally 코드 블록과 변수 스코프가 다른 문제)
    • catch 이후에 finally 호출, 자원 정리가 조금 늦어진다.
    • 개발자가 실수로 close() 를 호출하지 않을 가능성, close() 호출 순서를 실수할 가능성 존재

/자원 정리4 : try-with-resources 로 개선

  • Resource 객체가 AutoCloseable 을 구현하도록 하고, close()를 override 해주자.
  • try (자원 선언과 동시에 할당) 하고, catch 문에서는 단순히 CallException을 던지도록 해주자.
    • CallException이 발생하면, try-with-resources 로 인해 close() 를 자동 호출하게 된다.
    • close() 내에서 발생하는 예외는 어떻게 처리될까?
      • try-with-resource는 close 중에 발생한 예외는 핵심 예외가 아니라고 생각하고 예외가 원래 발생되었던 CallException에 closeException을 넣어준다.(Suppressed) 결국에는 CallException이 던져진다.
  • try-with-resources 장점
    • 리소스 누수 방지, 코드 간결성 및 가독성 향상, 스코프 범위 한정, 조금 더 빠른 자원 해제, 자원 정리 순서
    • 부가 예외 포함
      • 부가 예외는 핵심 예외안에 Suppressed 로 담아서 반환한다.
      • 개발자는 자원 정리 중에 발생한 부가 예외를 e.getSuppressed() 를 통해 활용할 수 있다.
  • try-with-resources는 항상 사용할 수 있는게 아니다. 어떤 경우에는 지저분하게 처리해야 한다

Ref) 김영한의 실전 자바 - 고급 2편, I/O, 네트워크, 리플렉션 강의 | 김영한 - 인프런

'Java > IO, Network' 카테고리의 다른 글

[Java] 52. 채팅 프로그램(feat. Command Pattern)  (0) 2025.07.01
[Java] 51. 네트워크 - 프로그램(2)  (0) 2025.07.01
[Java] 49. File, Files  (0) 2025.07.01
[Java] 48. 자바 I/O 활용  (0) 2025.07.01
[Java] 47. 자바 IO 기본(2)  (0) 2025.07.01
'Java/IO, Network' 카테고리의 다른 글
  • [Java] 52. 채팅 프로그램(feat. Command Pattern)
  • [Java] 51. 네트워크 - 프로그램(2)
  • [Java] 49. File, Files
  • [Java] 48. 자바 I/O 활용
lumana
lumana
배움을 나누는 공간 https://github.com/bebeis
  • lumana
    Brute force Study
    lumana
  • 전체
    오늘
    어제
    • 분류 전체보기 (463)
      • 개발 일지 (0)
        • Performance (0)
        • TroubleShooting (0)
        • Refactoring (0)
        • Code Style, Convetion (0)
        • Architecture (0)
      • Software Engineering (36)
        • Test (8)
        • 이론 (18)
        • Clean Code (10)
      • Java (72)
        • Basic (5)
        • Core (21)
        • Collection (7)
        • 멀티스레드&동시성 (13)
        • IO, Network (8)
        • Reflection, Annotation (3)
        • Modern Java(8~) (13)
        • JVM (2)
      • Spring (53)
        • Framework (12)
        • MVC (23)
        • Transaction (3)
        • AOP (11)
        • Boot (0)
        • AI (0)
      • DB Access (16)
        • Jdbc (1)
        • JdbcTemplate (0)
        • JPA (14)
        • Spring Data JPA (0)
        • QueryDSL (0)
      • Computer Science (130)
        • Data Structure (27)
        • OS (14)
        • Database (10)
        • Network (21)
        • 컴퓨터구조 (6)
        • 시스템 프로그래밍 (23)
        • Algorithm (29)
      • HTTP (8)
      • Infra (1)
        • Docker (1)
      • 프로그래밍언어론 (15)
      • Programming Language(Sub) (77)
        • Kotlin (1)
        • Python (25)
        • C++ (51)
        • JavaScript (0)
      • FE (11)
        • HTML (1)
        • CSS (9)
        • React (0)
        • Application (1)
      • Unix_Linux (0)
        • Common (0)
      • PS (13)
        • BOJ (7)
        • Tip (3)
        • 프로그래머스 (0)
        • CodeForce (0)
      • Book Review (4)
      • Math (3)
        • Linear Algebra (3)
      • AI (7)
        • DL (0)
        • ML (0)
        • DA (0)
        • Concepts (7)
      • 프리코스 (4)
      • Project Review (6)
      • LegacyPosts (11)
      • 모니터 (0)
      • Diary (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
lumana
[Java] 50. 네트워크 - 프로그램(1)
상단으로

티스토리툴바