네트워크 프로그래밍

이 책 내용을 기반으로 간략히 요약하여 정리했습니다.
IP 주소는 컴퓨터에게는 훌륭하지만, 긴 숫자를 기억하기 힘들어하는 인간에게는 문제입니다.
최대 12자리의 십진수로 구성된 IP 주소는 대부분의 인간이 기억할 수 있는 용량을 넘어섭니다.
이를 해결하기 위해 도메인 네임 시스템 (DNS)가 발명되었습니다.
DNS는 login.ibilio.org와 같이 인간이 기억할 수 있는 호스트 이름(hostname)을
152.19.134.132와 같이 컴퓨터가 기억할 수 있는 IP 주소와 연결해 줍니다.
복잡한 IP 주소 대신 외우기 쉬운 문자 이름(도메인)을 IP 주소로 변환합니다.
하나의 도메인 이름에 여러 IP를 연결하여, 접속량이 많을 때 트래픽 여러 서버로 분산이 가능합니다.
로컬 DNS 서버가 모르는 주소는 외부(상위) DNS 서버에 물어보고 결과를 전달합니다.
InetAddress address = InetAddress.getByName("www.oreilly.com");
실제 로컬 DNS 서버에 연결하여 이름과 숫자 주소를 찾습니다.
InetAddress address = InetAddress.getByName("208.201.239.100");
이처럼 역방향 조회(reverse lookup)도 가능합니다.
만약, 호스트의 모든 주소가 필요하다면
InetAddress[] address = InetAddress.getAllByName("www.oreilly.com");
배열을 반환하는 getAllbyName() 메서드를 사용해야 합니다.
new InetAddress()는 불가능합니다.
반드시 getByName(), getAllName(), getLocalHost()와 같은 정적 메서드를 사용합니다.
위 메서드들은 기본적으로 DNS 서버와 통신하여 주소를 찾기 때문에 네트워크 연결이 필요합니다.
DNS 캐싱: 자바는 성능을 위해 DNS 조회 결과를 캐싱합니다. (저장)
IP로 객체 생성시 주의점:
DNS 조회 제한: 신뢰할 수 없는 코드(예: 애플릿)는 임의의 도메인에 대해 DNS 조회가 불가능합니다.
오직 자신이 온 곳(Origin)만 조회 가능합니다.
정보 유출 위험: DNS 쿼리 자체에 데이터를 달아 전송하는 'DNS 커널링' 기법을 통해 정보가 유출될 수 있기 때문에 원천 차단합니다.
로컬 호스트 보호: 보안을 위해 getLocalHost()를 호출해도 실제 내부 IP가 아닌 루프백 주소(127.0.0.1)만 반환하여 내부망 구조를 숨깁니다.
불변 객체: Inet Address는 한 번 생성되면 변경할 수 없어 안전합니다.
호스트 이름 조회
바이트 처리 주의: getAddress()로 받은 바이트 배열에서 127보다 큰 수는 음수로 보일 수 있습니다.(signed)
반드시 +256을 해서 int로 변환해줘야 합니다.
버전 확인: getAddress().length가 4 또는 16으로 IPv4와 IPv6을 구분합니다.
주소 식별: 자바는 IP 주소가 어떤 용도(일반, 루프백, 멀티캐스트 등)인지 판별하는 메서드를 제공합니다.
보안 및 라우팅: LinkLocal이나 SiteLocal같은 주소는 외부 인터넷으로 라우팅 되지 않습니다.
-> 보안 및 내부 통신용으로 중요합니다.
127.0.0.1: 루프백 주소, 유니캐스트(멀티캐스트 X)
192.168.254.32: 사이트 로컬 주소(사설 IP), 유니캐스트
www.oreilly.com: 글로벌 주소, 유니캐스트
224.0.2.1: 글로벌 멀티캐스트 주소
FF01::1: 인터페이스 로컬(Node-local) 멀티캐스트 주소
(FE80 접두사는 링크 로컬 주소를 의미합니다.)
하드웨어 제어: NetworkInterface는 물리적 랜카드나 가상 인터페이스를 자바 객체로 표현한 것입니다.
생성 방법: getByName(이름), getByInetAddress(IP), getNetworkInterface(전체 목록) 메서드를 통해서만 객체를 얻을 수 있습니다.
OS 차이: 인터페이스의 이름(eth0, wlan0 등)은 OS마다 다릅니다.
용도: 주로 내 컴퓨터가 가진 모든 IP 주소를 확인하거나, 특정 네트워크 카드를 통해서만 통신하도록 설정할 때(멀티캐스트 등에서 중요) 사용됩니다.
정보 추출: NetworkInterface 객체는 주로 그 안에 할당된 IP 주소 목록이나 이름을 확인하는 용도로 쓰입니다.
다중 IP: 하나의 랜카드(인터페이스)에 여러 IP가 있을 수 있으므로 getInetAddress()는 단일 값이 아닌 Enumeration(목록)을 반환합니다.
DNS의 속도 활용: 스팸 여부 확인은 엄청난 양의 요청을 처리합니다.
-> 무거운 웹(HTTP)이나 DB연결 대신, 속도가 빠르고 전 세계적으로 캐싱이 잘 되는 DNS 시스템을 활용합니다.
역방향 질의 기법(Reverse Query)
1. 검사할 IP(A.B.C.D)의 순서를 뒤집습니다. (D.C.B.A)
2. 여기에 블랙리스트 서비스 도메인을 붙여(D.C.B.A.sbl.spamhaus.org) DNS에 물어봅니다.
3. 조회 성공: 해당 IP가 블랙리스트 명단에 있으니 스팸으로 판단합니다.
구현 디테일: IP 주소를 뒤집기 위해 바이트 배열을 다룰 때, 자바의 byte는 부호가 있으니 반드시 양수변환(+256)을 하여 문자열로 만들어줍니다.
전략: 웹 서버의 부하를 줄이기 위해 로그의 IP 변환(Reverse Lookup)은 나중에 별도로 처리합니다.
병목 현상: 단순 반복문으로 처리하면 DNS 대기 시간(Latency) 때문에 속도가 매우 느립니다.
해결책: ExecutorService(스레드 풀)를 사용하여 여러 DNS 조회를 병렬로 수행합니다.
CPU가 아닌 네트워크 대기시간이 주된 작업이므로 멀티 스레딩의 효과가 극적입니다.
순서 유지: Future 객체를 큐에 순서대로 저장했다가 꺼냄으로써, 병렬로 처리하면서도 로그의 기록이 섞이지 않게 유지합니다.