[학습 목표]
1. Java의 Socket과 ServerSocket을 활용하여 기본적인 TCP 통신 구조를 설계하고 구현할 수 있다. Socket , ServerSocket, DatagramSocket 등의 클래스 이해, TCP(연결형) , UDP(비연결형) 구조 비교 , 클라이언트 –서버 간 메시지 송수신 실습 2. 멀티 클라이언트 처리를 위한 스레드 기반의 서버 구조를 설계할 수 있다. 접속당 1스레드 구조 vs 스레드풀 구조 , 메시지 브로드캐스트 구현, 동시 접속 처리 시 고려할 예외 / 자원 관리 등 실습 3. 자바의 InetAddress 및 포트 , IP 기반 주소 체계를 이해하고 활용할 수 있다. InetAddress, getHostName(), getHostAddress() 등 주요 API 사용, 도메인과 IP 주소 매핑 , 포트 충돌 , 바인딩 오류 등 실습 기반 디버깅 4. 객체 직렬화를 통한 소켓 기반 객체 전송 구조를 구현할 수 있다. ObjectOutputStream/ ObjectInputStream 활용, 사용자 정의 객체 전송 및 수신, 직렬화와 네트워크 지연 , 보안 고려사항 등 분석 |
추가적인 요소
1) 아무런 락 없이 실행시켜보기
package com.sec17.appletree;
public class AppleTreeCase1_Bug extends AppleTreeCompetition {
protected boolean pickApple(String who) {
if (apples <= 0) return false;
apples--;
if (who.equals("Cat")) catCount++;
else dogCount++;
System.out.println(who + "가 사과를 땄습니다. 남은 사과: " + apples);
try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { }
return true;
}
}
위 코드는 lock이나 synchronized 또는 비동기 없이 공유 자원인 apples에 두 개의 스레드가 접근한 것이다. 이를 실행시킬 경우 동기화 처리가 없기 때문에 실행 도중 고양이와 강아지가 동시에 사과를 따는 일이 발생하게 된다. 그 결과 사과의 값이 올바르게 감소하지 않거나 예기치 않게 값이 증가하는 등 데이터 불일치 현상이 발생한다.
2) synchronized 이용하여 실행시켜보기
public class AppleTreeCase2 extends AppleTreeCompetition {
protected synchronized boolean pickApple(String who) {
if (apples <= 0) return false;
apples--;
if (who.equals("Cat")) catCount++;
else dogCount++;
System.out.println(who + "가 사과를 땄습니다. 남은 사과: " + apples);
try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { }
return true;
}
}
위 코드는 synchronized를 이용하여 임계 영역 (Critical Section)을 보호하기 위한 자바의 키워드 지정하였다.
고양이와 강아지가 각각 사과에 접근하게 되어 첫번째 코드처럼 오류가 발생하지 않는다.
임계영역이란?
두 개 이상의 스레드가 동시에 접근하면 안되는 코드 블록을 말한다.
3) wait() / notifyAll() 이용하여 실행시켜보기
public class AppleTreeCase3_WaitNotify extends AppleTreeCompetition {
private final Object lock = new Object();
protected boolean pickApple(String who) {
synchronized (lock) {
while (apples <= 0) {
try {
lock.wait(); // 대기풀에서 대기번호를 들고 기다림 -> 조건이 만족할 떄(notifyAll)까지 스레드 정지
return false;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
apples--;
if (who.equals("Cat")) catCount++;
else dogCount++;
System.out.println(who + "가 사과를 땄습니다. 남은 사과: " + apples);
lock.notifyAll(); // 대기풀에서 대기번호 받은 스레드는 다시 복귀
}
try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { }
return true;
}
}
lock을 사용하여 동시에 접근하지 못하도록 설정했다. wait()을 사용하여 대기풀에서 기다리게 한 다음 notifyAll()을 통해 대기풀에 있던 스레드가 실행되도록 하였다.
4) CompletableFuture 사용하여 실행시켜보기
import java.util.concurrent.CompletableFuture;
public class AppleTreeCase4_Async extends AppleTreeCompetition {
protected boolean pickApple(String who) {
CompletableFuture.runAsync(() -> {
synchronized (this) {
if (apples <= 0) return;
apples--;
if (who.equals("Cat")) catCount++;
else dogCount++;
System.out.println(who + "가 사과를 땄습니다. 남은 사과: " + apples);
}
});
try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { }
return true;
}
}
CompletableFuture을 사용하여 위 코드를 짜봤다. 이는 자바의 비동기 병렬처리의 핵심 클래스라고 말할 수 있다.
잠깐 코드를 살펴보겠다.
CompletableFuture.supplyeAsync().thenApply().thenAccept(System.out::println)
supplyeAsync() : 비동기 시작
thenApply() : 연산
thenAccept(Ssytem.out::println) : 출력
Future와 Callable은 결과를 반환하는 것으로 CompletableFuture는 리턴값이 있는 비동기의 개선된 확장형이라고 볼 수 있다.
여기서 Future의 단점은 예외처리가 어렵고 get() 결과를 기다릴 때 블록킹을 하여 후 작업을 할 수 없다는 것이 있다.
여기서 동기화와 비동기화에 대해 간략히 정리해보겠다.
동기화 : 작업이 끝날 때까지 기다렸다가 다음 작업으로 넘어가는 것 ( ex 전화 받을 때까지 전화하는 것)
비동기화 : 작업을 요청한 다음 , 결과를 기다리지 않고 바로 다음 작업으로 넘어가는 것 ( ex 내가 보내고 싶은 말들을 문자 메세지로 보내는 것)
5) 비동기화 lock 명시하여 실행시키기
import java.util.concurrent.locks.*;
// 비동기화 LOCK를 명시한 상황
public class AppleTreeCase5_AwaitSignal extends AppleTreeCompetition {
private final Lock lock = new ReentrantLock();
private final Condition notEmpty = lock.newCondition();
protected boolean pickApple(String who) {
lock.lock();
try {
while (apples <= 0) {
try {
notEmpty.await();
return false;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return false;
}
}
apples--;
if (who.equals("Cat")) catCount++;
else dogCount++;
System.out.println(who + "가 사과를 땄습니다. 남은 사과: " + apples);
notEmpty.signalAll();
} finally {
lock.unlock();
}
try { Thread.sleep((int)(Math.random() * 2)); } catch (InterruptedException e) { }
return true;
}
}
위 코드는 lock과 Condition을 사용하여 동시에 사과에 접근하지 못하도록 설정하였다.
네트워크와 네트워킹 기본 개념
정보 기술에서 네트워크는 통신 경로들에 의해 상호 연결된 일련의 지점(point)들이나 노드(node)들을 의미한다.
네트워킹이란 네트워크에 연결된 디바이스들 간의 데이터 교환을 의미한다
1) 프로토콜이란?
데이터 통신에서 통신 장치 간의 데이터 교환에 필요한 모든 규약의 집합체를 말한다.
물리적 측면의 프로토콜 : 데이터 전송에 사용되는 전송 매체 , 접속용 커넥터 및 전송 신호와 같은 물리적 요소를 말한다.
논리적 측면의 프로토콜 : 데이터의 표현 , 의미와 기능 , 데이터 전송절차 등을 의미한다.
2) 네트워크 기본 개념
네트워크를 통해 데이터를 전송할 때 비트로 전달하며 패킷을 사용한다. 패킷은 송신자아 수신자 주소와 패킷이 손상되지 않았음을 보장하기 위한 checksum과 네트워크로 전송할 떄 필요한 기타 유용한 정보들을 하는 헤더와 전송할 데이터를 바이트 그룹으로 포함하는 바디로 구분한다.
- OSI7 계층
여기서 우리가 살펴볼 것은 네트워크 계층이다.
네트워크 계층은 다른 장소에 위치한 두 시스템 간의 연결성과 경로 선택을 제공한다. 라우팅 프로토콜을 사용하여 서로 연결된 네트워크를 통한 최적의 경로를 선택하며, 선택된 경로를 따라 정보를 보낸다.
3) 중요 프로토콜
중요 프로토콜 중 IP와 TCP, UDP, HTTP / HTTPS 를 살펴보겠다.
IP : 데이터를 목적지까지 전달한다. IP 주소를 쓴다.
TCP : 신뢰성 있는 프로토콜로 중간에 데이터의 손실 없이 안전하게 전달되는 것을 보장한다. 또한 연결 지향이며 데이터를 순서대로 전송한다.
UDP : 빠르게 데이터를 전송하는 프로토콜이지만 그만큼 데이터 유실 가능성이 있다.
HTTP / HTTPS : 웹 브라우저에서 페이지를 불러올 떄 사용한다.
URL / URI
URL : 인터넷 상의 자원 위치를 나타낸다.
위치 (주소) + 프로토콜 (HTTPS 등) + 경로 정보
URI : 어떤 자원을 식별하기 위한 이름표와 같다.
위치 정보가 없어도 되고 이메일 주소나 데이터 식별자 등도 URI에 포함된다.
또한 URL도 URI의 한 종류이다.
예제를 살펴보겠다.
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.*;
import java.util.zip.GZIPInputStream;
public class Main {
public static void main(String[] args) throws InterruptedException {
String urlString = "https://www.python.org";
ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // 가상 스레드로 생성해서 작업
executor.submit(() -> { // 실행
try {
URL url = URI.create(urlString).toURL();
// GZIP 압축 해제 후 UTF-8로 읽기
try (InputStream rawStream = url.openStream();
InputStream decodedStream = new GZIPInputStream(rawStream);
BufferedReader reader = new BufferedReader(
new InputStreamReader(decodedStream, StandardCharsets.UTF_8))) {
System.out.println("\n [웹 페이지 내용 시작]");
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
System.out.println(" [웹 페이지 내용 끝]");
}
} catch (Exception e) {
System.err.println("오류 발생: " + e.getMessage());
}
});
executor.shutdown(); // 종료
executor.awaitTermination(10, TimeUnit.SECONDS);
}
}
위 코드는 웹 페이지의 내용을 가져와 GZIP압축을 해제한 후 UTF-8로 읽어 출력하는 코드이다.
+그 외 내용 ) java.net에서 InetAddress 클래스는 ip 주소를 표현하고 dns 조회 같은 작업을 수행할 수 있도록 해준다.
메소드는 이를 참고하면 좋다.
TCP/IP 프로토콜
ARPANET에서 임의의 서브네트웍을 통해 접속된 장비들의 종점간 연결과 라우팅을 제공하기 위해 미국 국방성에서 제정한 프로토콜이 TCP/IP 프로토콜이다.
여기서 ARPANET은 패킷 교환 네트워크를 말한다.
TCP / IP 프로토콜을 구성하는 주요 프로토콜을 IP와 TCP 이다.
IP는 인터넷에서 데이터 패킷을 목적지까지 전달하는 역할을 한다.
TCP/IP 프로토콜이라고 하면 TCP와 IP 두 프로토콜만을 지칭하는 것이 아니라 UDP , ICMP , ARP , RARP 등 관련된 프로토콜을 통칭하는 것이다.
ip -> routing [ 데이터 전송하기 위해서 최단의 경로를 설정 ]
네트워크 장비가 ip 주소를 기반으로 패킷을 포워딩 한다.
ICMP : ping IP -> 네트워크 오류 보고 , 진단
ARP : IP -> 물리적인 Mac 주소 변환
RARP : DHCP (Mac 주소를 IP로 변환)
'🦁멋쟁이 사자처럼 15기 > 4월달 수업 내용 정리' 카테고리의 다른 글
멋쟁이 사자처럼 41회차 ( 04 / 29 ) (2) | 2025.04.29 |
---|---|
멋쟁이 사자처럼 31회차 [ 04 / 15 ] (1) | 2025.04.15 |
멋쟁이 사자처럼 27회 ( 04 / 08 ) (0) | 2025.04.08 |
멋쟁이 사자처럼 26회 ( 04 / 07 ) (0) | 2025.04.07 |
멋쟁이 사자처럼 25회 ( 04 / 04 ) (0) | 2025.04.04 |