Ch 16.1 네트워킹 (Networking) 개요
네트워킹은 두 대 이상의 컴퓨터 혹은 디바이스들을 케이블이나 무선 통신망으로 연결하여 네트워크를 구성하고, 데이터를 주고받는 것을 의미합니다. 자바의 java.net 패키지를 사용하면 복잡한 네트워크 하드웨어 지식 없이도 손쉽게 네트워크 애플리케이션을 개발할 수 있습니다.
자바 네트워크 프로그래밍의 장점
자바는 OS에 독립적인 소켓 API를 제공하여, 동일한 코드가 Windows, Linux, macOS에서 동일하게 동작합니다.
1. IP 주소 (IP Address)
IP 주소는 네트워크 상에서 각각의 컴퓨터(호스트)를 식별하기 위해 부여되는 고유한 번호입니다.
| 항목 | IPv4 | IPv6 |
|---|---|---|
| 주소 형식 | 192.168.0.1 | 2001:0db8:85a3::8a2e:0370:7334 |
| 크기 | 32비트 (4바이트) | 128비트 (16바이트) |
| 최대 주소 수 | 약 43억 개 | 사실상 무한 |
| 현황 | 고갈 중 | 전환 진행 중 |
특수 IP 주소
127.0.0.1(localhost): 자기 자신을 가리키는 루프백 주소0.0.0.0: 모든 네트워크 인터페이스를 의미 (서버 바인딩 시 사용)255.255.255.255: 브로드캐스트 주소
2. 포트 (Port) 번호
IP 주소가 건물의 주소라면, 포트(Port) 는 그 건물 안에 있는 특정한 '방 번호'와 같습니다. 하나의 IP 안에서 여러 서비스가 구분되는 방식입니다.
- 범위: 0 ~ 65535
- 0 ~ 1023: Well-known Ports (시스템 예약)
- 1024 ~ 49151: Registered Ports (애플리케이션)
- 49152 ~ 65535: Dynamic/Private Ports
잘 알려진 포트 (Well-known Ports)
| 포트 | 프로토콜 | 설명 |
|---|---|---|
| 20, 21 | FTP | 파일 전송 |
| 22 | SSH | 보안 원격 접속 |
| 23 | Telnet | 원격 접속 (비보안) |
| 25 | SMTP | 이메일 발송 |
| 53 | DNS | 도메인 이름 해석 |
| 80 | HTTP | 웹 통신 |
| 443 | HTTPS | 보안 웹 통신 |
| 3306 | MySQL | 데이터베이스 |
| 5432 | PostgreSQL | 데이터베이스 |
| 6379 | Redis | 캐시 |
| 8080 | HTTP Alt | 개발용 웹 서버 |
3. TCP vs UDP 비교
| 항목 | TCP | UDP |
|---|---|---|
| 연결 방식 | 연결 지향 (3-way handshake) | 비연결 |
| 데이터 전달 보장 | 보장 (ACK 확인) | 보장 안 함 |
| 순서 보장 | 보장 | 보장 안 함 |
| 오류 감지/재전송 | 있음 | 없음 |
| 속도 | 상대적으로 느림 | 빠름 |
| 오버헤드 | 큼 | 작음 |
| 자바 클래스 | Socket, ServerSocket | DatagramSocket, DatagramPacket |
| 사용 사례 | HTTP/HTTPS, FTP, 이메일 | DNS, 스트리밍, 게임, VoIP |
4. java.net 패키지 주요 클래스
java.net
├── InetAddress IP 주소 표현 및 DNS 조회
├── URL URL 파싱 및 표현
├── URLConnection URL 연결 추상 클래스
├── HttpURLConnection HTTP 연결 구현체
├── Socket TCP 클라이언트 소켓
├── ServerSocket TCP 서버 소켓
├── DatagramSocket UDP 소켓
├── DatagramPacket UDP 패킷 (데이터그램)
├── MulticastSocket UDP 멀티캐스트 소켓
└── URI URI 표현 (URL보다 엄격)
5. InetAddress: IP 주소 조회
import java.net.*;
public class InetAddressExample {
public static void main(String[] args) throws UnknownHostException {
// 1. 로컬 호스트 정보
InetAddress localhost = InetAddress.getLocalHost();
System.out.println("호스트 이름: " + localhost.getHostName());
System.out.println("로컬 IP: " + localhost.getHostAddress());
// 2. 도메인 이름으로 IP 조회 (DNS 조회)
InetAddress google = InetAddress.getByName("www.google.com");
System.out.println("구글 호스트: " + google.getHostName());
System.out.println("구글 IP: " + google.getHostAddress());
// 3. IP 주소로 직접 InetAddress 생성
InetAddress byIP = InetAddress.getByName("8.8.8.8"); // Google DNS
System.out.println("8.8.8.8 호스트: " + byIP.getHostName());
// 4. 도메인에 여러 IP가 있는 경우 (로드 밸런싱)
InetAddress[] naverIPs = InetAddress.getAllByName("www.naver.com");
System.out.println("\n네이버 IP 목록:");
for (InetAddress ip : naverIPs) {
System.out.println(" " + ip.getHostAddress());
}
// 5. 루프백 체크
System.out.println("\n루프백 여부: " + localhost.isLoopbackAddress());
// 6. 도달 가능 여부 확인 (ping과 유사)
try {
boolean reachable = google.isReachable(3000); // 3초 타임아웃
System.out.println("구글 접속 가능: " + reachable);
} catch (Exception e) {
System.out.println("접속 확인 실패: " + e.getMessage());
}
}
}
6. 클라이언트-서버 모델
대부분의 네트워크 애플리케이션은 클라이언트-서버(Client-Server) 모델을 따릅니다.
[클라이언트] [서버]
| |
|--- 연결 요청 (connect) -----> |
| |--- accept() 후 새 Socket 생성
|<-- 연결 수락 (accept) ------- |
| |
|--- 요청 전송 (request) -----> |
| |--- 처리
|<-- 응답 수신 (response) ----- |
| |
|--- 연결 종료 (close) -------> |
import java.net.*;
public class ClientServerConcept {
// 서버 역할: 특정 포트에서 클라이언트 연결 대기
static void serverRole() throws Exception {
// 1. 포트 8080에서 리스닝 시작
ServerSocket serverSocket = new ServerSocket(8080);
// 2. 클라이언트 연결 대기 (블로킹)
Socket clientSocket = serverSocket.accept(); // 연결 수락
System.out.println("클라이언트 연결: " + clientSocket.getInetAddress());
// 3. 통신 후 자원 해제
clientSocket.close();
serverSocket.close();
}
// 클라이언트 역할: 서버에 연결
static void clientRole() throws Exception {
// 서버 IP와 포트로 연결 요청
Socket socket = new Socket("127.0.0.1", 8080);
System.out.println("서버 연결 완료. 로컬 포트: " + socket.getLocalPort());
System.out.println("서버 주소: " + socket.getInetAddress() + ":" + socket.getPort());
socket.close();
}
public static void main(String[] args) {
System.out.println("클라이언트-서버 모델 개념 예제");
System.out.println("서버: ServerSocket.accept()로 연결 대기");
System.out.println("클라이언트: new Socket(host, port)로 연결 요청");
}
}
7. 소켓(Socket)이란?
소켓(Socket)은 네트워크 통신의 끝점(Endpoint) 입니다. 두 프로그램이 네트워크를 통해 통신하려면 각각 소켓을 만들고 연결해야 합니다.
소켓은 다음 4가지 정보로 식별됩니다:
- 출발지 IP 주소
- 출발지 포트 번호
- 목적지 IP 주소
- 목적지 포트 번호
[클라이언트 소켓] [서버 소켓]
IP: 192.168.1.10 IP: 192.168.1.100
Port: 54321 <--> Port: 8080
8. HTTP 통신 기초
HTTP(HyperText Transfer Protocol)는 웹 브라우저와 웹 서버 간 통신 규약입니다.
HTTP 요청 메서드
| 메서드 | 용도 | CRUD |
|---|---|---|
| GET | 데이터 조회 | Read |
| POST | 데이터 생성 | Create |
| PUT | 데이터 전체 수정 | Update |
| PATCH | 데이터 일부 수정 | Update |
| DELETE | 데이터 삭제 | Delete |
HTTP 상태 코드
| 코드 | 의미 |
|---|---|
| 200 OK | 요청 성공 |
| 201 Created | 리소스 생성 성공 |
| 400 Bad Request | 잘못된 요청 |
| 401 Unauthorized | 인증 필요 |
| 403 Forbidden | 권한 없음 |
| 404 Not Found | 리소스 없음 |
| 500 Internal Server Error | 서버 내부 오류 |
9. 실전 예제: InetAddress로 도메인 IP 조회 도구
import java.net.*;
import java.util.*;
public class DNSLookupTool {
/**
* 도메인의 모든 IP 주소와 상세 정보를 조회
*/
static void lookupDomain(String domain) {
System.out.println("\n=== " + domain + " 조회 ===");
try {
// DNS 조회
InetAddress[] addresses = InetAddress.getAllByName(domain);
System.out.println("IP 주소 수: " + addresses.length);
for (InetAddress addr : addresses) {
String type = addr instanceof Inet6Address ? "IPv6" : "IPv4";
System.out.printf(" [%s] %s%n", type, addr.getHostAddress());
// 루프백, 사이트 로컬, 링크 로컬 여부
System.out.printf(" 루프백: %b, 사이트로컬: %b%n",
addr.isLoopbackAddress(), addr.isSiteLocalAddress());
}
} catch (UnknownHostException e) {
System.out.println("알 수 없는 호스트: " + domain);
}
}
static void showLocalNetworkInfo() throws Exception {
System.out.println("=== 로컬 네트워크 정보 ===");
InetAddress local = InetAddress.getLocalHost();
System.out.println("컴퓨터 이름: " + local.getHostName());
System.out.println("로컬 IP: " + local.getHostAddress());
System.out.println("IPv6 여부: " + (local instanceof Inet6Address));
// 네트워크 인터페이스 목록
System.out.println("\n네트워크 인터페이스 목록:");
Enumeration<NetworkInterface> nets = NetworkInterface.getNetworkInterfaces();
while (nets.hasMoreElements()) {
NetworkInterface nic = nets.nextElement();
if (nic.isUp() && !nic.isLoopback()) {
System.out.println(" " + nic.getDisplayName());
Enumeration<InetAddress> addrs = nic.getInetAddresses();
while (addrs.hasMoreElements()) {
System.out.println(" IP: " + addrs.nextElement().getHostAddress());
}
}
}
}
public static void main(String[] args) throws Exception {
showLocalNetworkInfo();
// 잘 알려진 도메인 조회
lookupDomain("localhost");
lookupDomain("www.google.com");
lookupDomain("invalid.domain.xyz"); // 없는 도메인
}
}
고수 팁: 소켓 통신 레이어
자바 소켓은 OS의 TCP/IP 스택을 래핑한 것입니다. 내부적으로는 OS가 실제 패킷 조립/분해, 오류 감지, 재전송을 담당합니다. 자바 코드는 스트림(InputStream/OutputStream)으로 추상화된 인터페이스를 통해 데이터를 주고받습니다.