이 글은 성공과 실패를 결정하는 1%의 네트워크 원리 책(이도희 역)을 기반으로 재구성한 것입니다.
이전 포스팅에서 인터넷에서 나온 packet이 server의 load balancer나 방화벽, proxy를 거쳐 server에게 도달하는 것까지 살펴봤다. 이 장에서는 server가 어떤 과정을 거쳐 packet을 수신하는지 다뤄 볼 것이다. 대부분 내용은 앞에서 설명한 내용을 받는 내용이기 때문에 거의 유사할 것이다.
Server
request message에서 data 위치를 파악하고 그 값을 client에게 넘긴다는 것이 web server의 기본적인 동작이다.
client와의 차이점
일단, server는 client가 보낸 요청을 처리하고 거기에 답을 한다. 그렇지만 LAN adapter, OS protocol stack, socket library 등의 network 관련 기능은 client와 모두 동일하다.
그렇지만 socket library에서 사용하는 함수가 다르다. server는 기동 후 여러 가지 준비 동작을 하며, 시작한 후 client access를 대기하는 상태가 되며, 이를 수행하는 함수를 호출한다.
server의 구조
server는 n개의 client와 통신을 수행하지만 하느이 program으로 n개의 통신을 처리하기는 어렵다. 때문에 server-client가 1:1로 대화하는 방법이 일반적이다.
이를 위해서는 아래 2가지를 만든다.
- 접속을 기다리는 부분, (위 그림에 (a)). socket을 생성하고 연결이 올 때까지 기다린다.
- client와 대화하는 부분, (위 그림에서 (b), (c)). 연결이 완료되면 여기서 client와 통신한다.
2번 부분은 client와 1:1이며 여러 개가 만들어지는데, multi thread가 이를 작동시킨다.
TCP connection - Server vs Client
앞서 설명했듯 통신은 대칭적으로 왔다갔다 하기 때문에 client와 server의 큰 차이는 없다. 그러나 항상 좌우 대칭으로 만들 수 없는 부분 중 하나가 TCP 접속 동작이다. 한 쪽은 대기해야만 하고, 한 쪽은 연결해야만 한다.
flow로 차이를 한 눈에 보면 아래와 같다.
client의 경우 | server의 경우 | |
1 | socket 작성 | socket 작성 |
2 | server socket에 연결 | 1) 접수 대기 상태로 만듬 2) 접속을 접수함 |
3 | data 송/수신 | data 송/수신 |
4 | session 종료, socket 말소 | session 종료, socket 말소 |
소스코드로 표현하면 아래와 같다. 바로 아래는 1%의 네트워크 - 1. 웹 브라우저가 하는 일 포스팅에서 client측의 소스코드이다.
ip = gethostbyname("hyeile.tistory.com");
socket_desciptor = socket(); // ... socket 생성
connect(socket_desciptor, ip:port, ...); // 접속
write(socket_descriptor, ...); // 송신
result = read(socket_descriptor, ...): // 수신
close(socket_descriptor); // 연결 끊기
server측 로직을 소스코드로 표현하면 아래와 같다.
// 접속 대기 부분
// ... socket 생성
socket_descriptor = socket(...)
// 접속 대기 상태로 만듬
bind(socket_descriptor, port, ...);
listen(socket_descriptor, ...);
// 접속 접수
accept_descriptor = accept(socket_descriptor, ...);
//////////////////
// 대화 부분
// data 수신
result = read(accept_descriptor, buffer, ...);
// ... request 처리
// data 송신
write(accept_descriptor, ...);
close(accept_descriptor, ...);
// 연결 끊기
close(socket_descriptor)
- socket() : socket 생성.
- bind() : socket port number 기록하고, 해당 port로 client가 접속하기를 기다린다.
- listen() : socket 접수 대기. client가 들어오면 accept() 호출
- accept() : 접속 접수. 만약 client가 오지 않은 상태면 대기한다. client의 접속 요청 packet이 오면 대기중인 socket을 복사해 새로운 socket을 만든다.
접속 시에는 새로운 socket을 만드는 것이 아니라 접속 대기 상태의 socket을 그대로 두고 사본을 만들어 TCP connection을 진행한다. 만약 접속 대기 상태 socket에 바로 접속하면 해당 socket이 사라져 버리기 때문에 다음 client가 같은 port로 접속하지 못하기 때문이다.
때문에 새 socket을 만들 때 port 번호가 요점이다. port 번호는 network service나 process를 식별하기 위한 번호라고 했다. 때문에 port만으로는 client의 연결 요청에 대한 식별을 하지 못한다. 이를 해결하기 위해 [client IP address, client port, server IP address, server port] 4가지 정보를 사용해 socket을 식별한다.
즉, server socket은 같은 port를 가진 socket이 여러 개 존재하게 된다!
참고로 descriptor 이용해 socket 식별하는 이유는, [client IP address, client port, server IP address, server port] 4가지 정보를 사용해 socket을 식별하는 것보다 descriptor가 더 간단하고, 또 socket 생성 직후에는 정보가 없기 때문에 정보가 없는 socket도 식별할 수 있어야 하기 때문이다.
Server의 수신 동작
이제부터는 앞에서 설명한 내용의 역순으로 진행된다.
LAN adapter
인터넷 내부의 provider의 PoP나 NOC, access 회선, router, hub를 거쳐 server에게 도착한 전기 신호는 LAN adapter가 수신한다. LAN adapter의 수신 동작도 송신 동작의 역순이다.
- preamble에서 clock을 추출한다.
- clock을 사용해 신호를 digital data로 변환한다.
- FCS, Frame Check Sequence를 사용해 packet의 오류 유무를 검사한다.
- 올바르면 수신하고, 아니라면 폐기한다.
- 수신한 경우, MAC header에 있는 수신처 MAC address를 조사해 자신에게 보낸 것인지 확인한다.
- 맞다면 수신하고, 아니면 폐기한다.
- ethernet의 경우 subnet에 모든 packet을 뿌리기 때문에 자신에게 온 것이 아닐 수도 있기 때문이다.
- 맞는 경우 LAN adapter의 buffer에 저장한다.
이 때 CPU는 packet 도착을 모르기 때문에 interrupt를 사용해 LAN adapter가 CPU에게 packet 도착을 알린다. 그러면 CPU는 LAN driver를 실행시켜 buffer에서 packet을 추출하고 MAC header field에 따라 protocol을 판별한 후 해당 protocol을 처리하는 software를 호출한다.
IP
OS protocol stack에 packet이 전달되면 IP header를 조사해 자신에게 온 것인지 확인한다. 만약 자신에게 온 것이면 IP header의 fragmentation field를 조사해 분할된 경우 memory에 저장하고 나머지 packet을 모두 합쳐 원래 data로 복구한다. 이후 IP header의 protocol field에 따라 적당한 담당 부분에게 packet을 건네준다.
TCP
이 글에서는 TCP에게 packet을 건넨 경우를 가정한다. TCP에는 크게 3가지 동작이 있다. 각각 동작에 따라 어떤 일을 하는지 살펴보자. 1%의 네트워크 - 2. OS Protocol Stack과 LAN Adapter 포스팅에서 TCP 관련 내용을 볼 수 있다.
- control bit(SYN)이 1인 경우 접속 동작의 packet이다. 수신처 port를 확인하고, 해당 port에서 대기하는 socket이
- 있는 경우 - 새 socket에 packet 정보(송신처 IP address, port, window, sequence 등)을 넣고, ACK와 server window, sequence를 송신한다.
- 없는 경우 - ICMP messgage를 송신한다.
- data 송/수신 packet 도착 시 - [송/수신처 IP address, 송/수신처 port] 4개 정보를 사용해 socket를 찾는다.
- 있는 경우 sequence 값 계산, sequence 번호 합쳐 계산, 등 송/수신 동작을 점검한다.
- 수신 확인 응답용 [window, 수신 sequence 번호, ACK 번호]를 담은 TCP header를 송신한다.
- application이 read()를 호출하기 전까지 buffer에 정보를 저장해 둔다.
- 연결 끊기 시
- web의 경우 server에서 먼저 연결을 끊으므로, 이 경우를 보자.
- server application이 socket close()를 호출하면 TCP는 FIN bit를 1로 설정한 TCP header를 보낸다.
- client에 해당 TCP packet이 도착하면 client는 ACK를 담은 TCP header를 반송한다.
- 이후 client는 socket close()를 호출하고, FIN bit를 1로 설정한 TCP header를 발송한다.
- server에 해당 TCP packet이 도착하면 server는 ACK를 담은 TCP header를 반송한다.
- 그러면 잠시 기다렸다가 socket을 삭제한다.
HTTP request message 의미 해석
socket read()를 호출하면 TCP에서 받은 data를 읽으며, 이 부분은 HTTP request message이다. (다른 정보를 보냈다면 해당 정보) request message에는 method와 URI가 있는데, 이를 사용해 값을 처리한다.
기본적으로 URI는 file path를 의미하는데, URI에 있는 file path를 실제 file path로 처리하면 해킹에 매우 취약해진다. 때문에 virtual directory를 만들고, URI를 virtual directory path로 취급해 해당 path에 있는 값을 가져온다.
위 예시에서 GET /doc이었다면 실제 server의 /usr/share/doc을 가져온다.
만약 URI가 file인 경우 그대로 응답하고 CGI, Common Gateway Interface인 경우 URI로 지정한 program을 OS가 실행시킨다.
access 제어
request message에서 data 위치를 파악하고 그 값을 client에게 넘긴다는 것이 web server의 기본적인 동작이라 설명했다. 이 동작을 수행할 때 특정 조건을 만족하는지 검사하고, 만족할 때만 수행할 수 있는 기능이 있는데 이를 access 제어라고 한다. 대표적으로 아래 3가지 조건으로 설정한다.
- client IP address : 이것으로 client IP address를 사용해 점검한다.
- client domain name : DNS server에 query를 날려 IP address로 domain name을 조사한다. client IP address와 client domain name이 일치해야만 통과시킨다.
- username, password : client가 해당 정보를 request message에 담아 보내면 web server가 username, password를 확인하고 허가 된 경우에만 response를 보낸다.
web browser가 응답을 화면에 표시
server가 보낸 response는 client가 받으며, 이를 response message라고 한다. web browser는 response message header에 있는 content-type field로 data 종류를 판별하고 content-encoding으로 압축 여부를 조사할 수 있으며, charset으로 문자를 판독할 수 있다.
이렇게 data와 data 종류를 읽었으면 화면에 출력한다. 출력은 경우에 따라 HTML, data, jp, program 등 여러 가지로 출력한다.
정리
지금까지 web browser에 url을 입력했을 때 어떤 과정을 거쳐 web server로 갔다가 받은 응답이 화면에 출력되는 것을 보았다. 한 번 더 내용을 생각해 보며 마무리하자.
잘못된 내용이나 오탈자에 대한 지적, 질문 등은 언제나 환영합니다.
'CS > Network' 카테고리의 다른 글
[Network] 하향식 접근 네트워크 - 2. Application Layer - (1) Application Principle (0) | 2023.07.27 |
---|---|
[Network] 하향식 접근 네트워크 - 1. Introduction (0) | 2023.07.26 |
[Network] 1%의 네트워크 - 5. Firewall, Proxy, Load Balance (0) | 2023.07.24 |
[Network] 1%의 네트워크 - 4. 인터넷 내부 (0) | 2023.07.24 |
[Network] 1%의 네트워크 - 3. Cable, Hub, Router (1) | 2023.07.21 |