본문 바로가기
지식/시스템프로그래밍

Network programming

by 칙칙폭폭 땡땡 2025. 6. 11.
반응형

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