IP address
ip 주소는 항상 메모리에 network byte order로 저장됨
네트워크 통신시에는 항상 network byte order 를 Big-endian byte order으로 맞춤. (약속)
Big-endian byte order
만약 IP 주소가 0x12345678
big-endian : 12 34 56 78
little-endian: 87 65 43 21
이런식으로 메모리에 저장됨.
컴퓨터마다 이걸 저장하는 방식은 다르지만 네트워크는 항상 big-endian으로 보냄
이걸 운영체제는 알고 있고 그냥 함수만 불러서 big이든 little이든 넣어주면 무조건 big-endian이 나옴
(보낼 때: htonl, htons 호스트 투 네트워크 롱 or 숏)
받을 때도 걍 함수 가져다가 쓰면 됨
(받을 때: ntohl, ntohs 네트워크 투 호스트 롱 or 숏)
여기서 12 34 56 78 이 숫자들은 16진수임.
0x12 → 16진수 12 → 16*1 + 2 = 18
0x34 → 16진수 34 → 16*3 + 4 = 52
0x56 → 16진수 56 → 16*5 + 6 = 86
0x78 → 16진수 78 → 16*7 + 8 = 120
⇒ 18.52 86.120 (dotted Decimal)
DNS

dotted name을 뒤에서부터 찾아서 dotted decimal을 리턴해줌
도메인은 뒤에서부터 점 단위로 역순으로 해석되고, DNS 서버들이 계층적으로 해석해 나가며 IP를 반환해줌.
Connection
socket의 주소는 Ip:port 쌍
port는 16비트 정수
Ephermeral port: 자동으로 할당되는 포트 Well-known port: 어떤 용도를 사용하기 위해 정해진 포트
Socket Address structure


sa_fmaily랑 sin_family는 어떤 프로토콜 쓸 건지 의미하는 부분
sa_data[14]의 크기가 sin_port, sin_addr, sin_zero[8] 의 크기와 일치
소켓 호출 함수들(connect, bind, accept)들은 반드시 주소를 struct addr * 형태로 받아야함
추가로 구조체 크기인 addrlen도 받음.
소켓 호출 함수를 호출하면 CPU가 system call 명령을 실행함. (여기서 유모드 → 커널모드)
커널 내 네트워크 스택(5계층)이 sa_family와 addrlen을 보고 소켓 구조체를 생성함.
알맞는 프로토콜 전용 포맷으로 바인딩(3-way handshaking) 처리해줌
처리 끝나면 커널모드 → 유저모드로 바뀌고 소켓 호출 함수의 결과를 리턴
getaddrinfo

getaddrinfo 는 호스트명과 서비스명을 소켓 주소 구조체(struct sockaddr)로 변환
hostname으로 dotted decimal주소 얻게 해주는 놈

host: 원격 서버 주소
service: 포트 (”http”→80, “ftp”→20, “8080”→8080
hints: 어떤 프로토콜인지, 소켓 타입 뭔지, 플래그 뭔지, … 미리 정해주는 곳
result: 성공하면 *result(구조체 리스트의 첫번째 노드 주소값)에 malloc된 구조체 리스트가 채워짐.

다 쓰고 나서 freeaddrinfo(*result) 해주어야함.
getnameinfo

방금 전에 getaddrinfo랑 정확히 반대 역할
dotted decimal로 hostname 알게 해주는 놈
example

입력으로 ./hostinfo localhost 했는데
localhost가 argv[1]로 들어감.
그 아래 예시도 마찬가지

hints에서 정보 미리 작성해서 밑에 getaddrinfo에 넣어줌
hints.ai_family = AF_INET에서 AF_INET은 IPv4의미
hints.ai_socktype = SOCK_STREAM에서 SOCK_STREAM은 소켓 타입
rc가 0이면 성공

flag는 걍 주소 출력하는 옵션임. 숫자로 출력하겠다.
p→ai_addr: 반환할 소켓 주소 구조체 포인터
p→ai_addrlen: 소켓 주소 구조체 크기
buf: 변환된 문자열 저장할 버퍼
MAXLINE: 버퍼 크기
NULL: 포트 문자열 자리
flags: 변환 옵션
Socket

클라이언트랑 서버 둘다 소켓 인터페이스 생성

domain: 프로토콜 패밀리
type: 소켓 타입
protocol: 좀 더 세부 프로토콜

클라이언트에서는 소켓 디스크립터를 위처럼 사용
example

위 코드 주석 3에서 2에서 getaddrinfo로 받아온 리스트의 첫번째 노드로 연결 시도하는 모습
bind


bind는 어떤 소켓에 대해서 어떤 포트를 쓸 건지 명시적으로 지정해주는 것
addr에서 주소는 항상 내 주소고 포트 번호는 다 다를 수 있음.
이건 서버만 하는 것.
서버가 해당 포트 번호에 대한 소켓을 생성한다고 생각.
listen


listen은 서버의 소켓을 클라이언트 연결을 기다리는 “수신 대기용 소켓”으로 “전환”하는 것.
socket() → bind() 까지 한 소켓 디스크립터를 가지고 이 소켓으로 들어오는 연결 요청을 처리
backlog는 동시 대기 가능한 연결 요청의 최대 개수, accpet() 안된 애들을 큐에 쌓아 두는 것
socket()만 하면 active 소켓 상태 = 클라이언트처럼 “내가 먼저 연결을 걸겠다”라는 상태
listen()을 하면 passive 소켓 상태 = 어떤 포트로 들어오는 연결 요청 처리하겠다.
accept


accept는 listening socket에서 들어오는 연결 요청을 “꺼내서” 실제 통신할 때 사용할 “새로운” 소켓 디스크립터를 생성해줌.
listenfd: 서버용 listening socket
addr: 클라이언트 주소를 저장할 버퍼 (ip,포트)쌍으로
addrlen: 버퍼 크기
accept에서 계속 대기하다가 연결 요청이 들어오면 TCP-3-way 핸드쉐이킹으로 새로운 connected socket 생성하고 그거 리턴해줌.
addr에 클라의 IP, port 정보를 주어진 버퍼의 크기 안에서 채움
addrlen은 채워지 바이트 수 리턴
connect


클라이트가 서버에 TCP 연결요청할 때 사용
addr: 서버의 IP와 포트 정보
TCP 연결은 4tuple: (클라IP:클라port, 서버IP:서버port)
클라이언트 포트는 보통 ephermeral port(커널에 의해서 자동으로 정해진 포트)
연결 성공하면 connect는 0 리턴
open_clientfd (클라이언트 단)
매번 getaddrinfo → socket → connect 아주 개귀찮다
한번에 하자 한번에!

hostname이랑 port만 주면 알아서 하도록
힌트는 위와 같이 통일하는 듯 함.
내부적으로 주어진 정보로 getaddrinfo를 호출하고 sockaddr 구조체 리스트 listp를 생성

for문으로 순회하면서 연결 가능한 소켓 주소 찾음. (찾으면 즉시 for문 탈출)
찾았으면 이제 연결 시도 성공했으니까 freeaddrinfo(listp)
연결된 clientfd가 있으면 그 녀석으로 소통해서 cliendfd 리턴
이 clientfd를 통해서 read, write이 가능하다.
open_listenfd
마찬가지로 매번 getaddrinfo → socket → bind → listen 너무 짜증나
힌번에 하자고요

포트 번호만 주면 알아서 그 포트 번호로 리스닝 소켓 개방
플래그를 AI_PASSIVE로 하고, getaddrinfo의 내 주소 쓰는 곳을 NULL이라고 작성했는데, 이 조합은 모든 주소로 들어오는 요청을 받겠다는 의미임.
인터페이스(특정 IP)에 국한 X
NULL의 의미는 내 주소들을 의미함(내 이더넷 주소, 내 루프백 주소, 내 무선 주소)

listp 돌면서 소켓 생성 시도
setsockopt은 소켓의 옵션 설정하는 부분.
그 밑에서는 생성된 리스닝 소켓에 내가 인자로 넘겼던 포트로 바인드 시도

리슨까지 성공하면 해당 리스닝 소켓으로 나중에 accept 대기해야되니까 listenfd를 리턴해줌.
'지식 > 시스템프로그래밍' 카테고리의 다른 글
Parallel Programming (1) | 2025.07.02 |
---|---|
Concurrent Programming (4) | 2025.07.02 |
System-Level I/O (1) | 2025.04.21 |
Exceptional Control Flow: Signals and Nonlocal Jumps (2) | 2025.04.10 |
Exceptional Control Flow: Exceptions and Processes (0) | 2025.03.29 |