
2025.05.04
오늘한 내용 : CS - 네트워크 프로그래밍 - 11.1 ~ 11.4
WEEK08: BSD소켓, IP, TCP, HTTP, file descriptor, DNS
| 구성 요소 | 설명 |
|---|---|
| 호스트 (Host) | 네트워크에 연결된 컴퓨터 (IP 주소 가짐) |
| 링크 (Link) | 호스트/라우터 간 실제 연결 (이더넷, Wi-Fi 등) |
| 라우터 (Router) | 패킷을 목적지로 전달하는 중간 장치 |
| 패킷 (Packet) | 데이터를 쪼갠 전송 단위 (헤더 + 본문) |
| 계층 | 역할 | 주요 예시 |
|---|---|---|
| 응용 계층 | 사용자 앱 – 데이터 생성 | HTTP, DNS |
| 전송 계층 | 프로세스 간 연결 | TCP, UDP |
| 인터넷 계층 | 호스트 간 라우팅 | IP |
| 링크 계층 | 홉 간 실제 전송 | Ethernet (MAC 주소) |
데이터는 위에서 아래로 내려가며 캡슐화됨:
HTTP 데이터
↓ (TCP 헤더 추가)
TCP 세그먼트
↓ (IP 헤더 추가)
IP 패킷
↓ (MAC 헤더 추가)
이더넷 프레임 → 네트워크로 전송
| 항목 | IP 주소 | MAC 주소 |
|---|---|---|
| 목적 | 최종 호스트 식별 | 홉 단위 전송 대상 |
| 범위 | 논리적, 전 세계 고유 | 물리적, 네트워크 인터페이스 |
| 라우팅 | 라우터가 IP로 다음 경로 판단 | NIC가 MAC으로 다음 홉 전달 |
| 변동성 | DHCP 등으로 변경 가능 | 고정 (수정 가능) |
[MAC 헤더][IP 헤더][TCP 헤더][데이터][체크섬]read(), write()를 네트워크 소켓에도 사용 가능 → 파일처럼 사용152.46.7.80192.168.0.1 → 내부적으로는 32비트로 저장됨htonl(), ntohl() 등이 있음컴퓨터가 여러 바이트로 구성된 데이터를 메모리에 저장하는 순서
대표적으로 2가지 방식:
| 종류 | 설명 | 예시 (0x12345678 저장 시) |
|---|---|---|
| 빅 엔디안 (Big-endian) | 가장 큰 바이트(상위 바이트)를 앞에 저장 | 12 34 56 78 |
| 리틀 엔디안 (Little-endian) | 가장 작은 바이트(하위 바이트)를 앞에 저장 | 78 56 34 12 |
네트워크는 무조건 빅 엔디안
| 함수 | 설명 |
|---|---|
htonl(x) | host → network (32비트 정수) |
htons(x) | host → network (16비트 정수) |
ntohl(x) | network → host (32비트 정수) |
ntohs(x) | network → host (16비트 정수) |
www.cmu.edu, google.comaddress:port/etc/services 파일에 저장됨(cliaddr:cliport, servaddr:servport)
예시:
128.2.194.242:51213 (임시 포트)208.216.181.15:80 (HTTP 서비스 포트)클라이언트와 서버는 서로 다른 순서로 함수 호출:
socket() – 소켓 생성connect() – 서버에 연결 요청read() / write() – 데이터 송수신socket() – 소켓 생성bind() – IP 주소와 포트를 소켓에 바인딩listen() – 연결 요청 대기accept() – 클라이언트 연결 수락read() / write() – 데이터 송수신sockaddr 구조체: 소켓 주소 정보를 담는 범용 구조체sockaddr_in: IPv4 주소용 구조체struct sockaddr_in {
uint16_t sin_family; // AF_INET
uint16_t sin_port; // 포트 번호(빅엔디안)
struct in_addr sin_addr; // IP 주소
unsigned char sin_zero[8];// 패딩
};
socket 함수int socket(int domain, int type, int protocol);
| 인자 | 설명 |
|---|---|
domain | 주소 체계: IPv4는 AF_INET |
type | 전송 방식: TCP는 SOCK_STREAM, UDP는 SOCK_DGRAM |
protocol | 보통 0 (자동 선택) |
connect 함수 (클라이언트용)int connect(int sockfd, struct sockaddr *addr, socklen_t addrlen);
addr은 보통 sockaddr_in을 sockaddr*로 캐스팅bind 함수 (서버용)int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen);
INADDR_ANY를 쓰면 모든 NIC에서의 연결 수락listen 함수int listen(int sockfd, int backlog);
backlog: 대기열 크기 (보통 8~128)bind() 후 호출해야 함accept 함수int accept(int listenfd, struct sockaddr *addr, socklen_t *addrlen);
addr에는 클라이언트의 주소 정보가 들어감read()/write() 가능getaddrinfo() 함수www.google.com)과 포트 번호("80")를 소켓 주소 구조체(struct sockaddr)로 변환해주는 함수int getaddrinfo(const char *hostname, const char *port,
const struct addrinfo *hints,
struct addrinfo **result);
struct addrinfo *res, hints;
memset(&hints, 0, sizeof(hints));
hints.ai_socktype = SOCK_STREAM;
getaddrinfo("www.google.com", "80", &hints, &res);
res는 연결에 사용할 수 있는 소켓 주소 리스트를 가리킴freeaddrinfo(res)로 해제해야 함반복되는 소켓 코드를 줄이기 위한 헬퍼 함수 정의
책에서는 다음 두 함수를 만들어서 클라이언트/서버 코드 간결화함:
open_clientfd(char *hostname, char *port)connect()까지 수행getaddrinfo() + socket() + connect() 전부 처리open_listenfd(char *port)listen()까지 수행getaddrinfo() + socket() + bind() + listen() 처리| 함수 | 용도 | 내부에서 하는 일 |
|---|---|---|
getaddrinfo() | 도메인 이름 → 소켓 주소 변환 | DNS + 포트 세팅 |
open_clientfd() | 클라이언트 소켓 생성 및 연결 | getaddrinfo + socket + connect |
open_listenfd() | 서버 리슨 소켓 설정 | getaddrinfo + socket + bind + listen |