API 서버가 데이터를 받기까지 (운영체제에서) - 서버가 작동하는 흐름 1

시리즈 목차

(현재글) 1.서버가 데이터를 받기까지 [운영체제에서]
2.서버가 데이터를 받기까지 [libuv]
3.서버가 받은 데이터가 어떻게 처리되는지. Node.js만의 방식이 어떤지 정리한다.
4.Node.js만의 방식을 하나하나 조금 더 디테일하게 - Event loop, Libuv, V8, JS



API 서버가 데이터를 받기까지.

우리가 만든 Node.js 서버가 데이터를 받기위해선 포트 번호(ex. 3000, 8080)와 바인딩되어야한다. 그래야만 운영체제가 node.js 서버 프로그램이 어디 있는지 알수있고 데이터를 보낼수 있다. 이제 포트와 연결된 상태로 서버가 실행중이라면 서버에서는 데이터를 받을 준비가 됐다.

송신자측을 이야기해보자. 송신자(클라이언트)는 데이터를 보내기전에 서버와 연결을 만들어야한다. 이때 TCP 연결이 필요하다. TCP 연결은 3 way handeshake로 만들어진다. 3 way handshake가 완료되면 클라이언트와 서버에 socket이 생긴다. 이 소켓(socket)이라는 건 connection이 가능하다는 증빙이라고 생각하면 된다. 소켓의 내용물는 클라이언트와 서버 양측 네트워크 정보[송신자 IP, 송신자 port, 수신자 IP, 수신자 port] 4가지이다. 이 증빙이 있으면 클라이언트에서 서버로 데이터를 보낼수 있게 된다.

송신자가 데이터를 보냈을 때 수신자측에서 소켓을 가지고 있지 않은 상태라면(소켓데이터가 유실되거나) 연결 리셋(TCP reset) 응답이 온다. 이때 송신자는 다시 3 way handshake을 진행해야한다. 그 뒤 양쪽에 소켓이 생성되면 데이터를 보낼수 있다.

클라이언트와 서버간의 연결이 확보되면 아래 layer들에서 데이터에 여러가지 정보를 덧붙인다.

  • TCP layer는 데이터 전송의 안정성 관련 정보,
  • IP layer는 목적지 ip까지 잘도착하는데에 필요한 정보,
  • 마지막으로 Data link layer는 목적지 IP에서 서버가 작동하고 있는 구체적인 하드웨어 정보를 담당한다. 그리고 네트워크에서 움직일수 있는 형태의 데이터로의 변환까지 책임진다.

TCP/IP stack에 대해 아주 짧게 정리하고 넘어가보자. (디테일에 대해선 다른 좋은글들이 많다. 네이버 D2 TCP/IP 네트워크 스택 이해하기)

Application layer

우리가 쓰는 chrome 등 모든 프로그램/앱이 application이다. application layer에서는 클라이언트와 서버가 소통하기로 한 방식에 맞게 보내는 데이터를 맞춰주는 역할을 한다. http, ftp등이 있는데 이들 모두 커뮤티케이션하는 방식이 다르므로 개별 구조에 맞추는 작업이다. Node.js에서는 http library가 이 일을 해준다.

데이터를 규약에 맞게 만들고 나면 위에서 얘기한 socket으로 데이터를 보낸다. 소켓의 “write socket buffer” 으로 보내게 되는데 이때 system call을 전송이 이루어진다.


TCP layer

write socket buffer에 데이터가 오게 되면 차례차례 필요한 데이터를 붙여준다. TCP layer는 데이터 전송의 안정성을 높여주는 것이 목적이라고 했다. 그래서 붙여주는 데이터들이 “순서 데이터”, “확인 응답 데이터”, “포트 번호”등이다.

순서 데이터

보통 클라이언트 요청이 하나의 패킷으로 전달되지않는다. 여러개로 나뉘어서 보내지는데, 네트워크 상태에 따라 순서대로 보내지지 않을 때가 많다. 이럴 때 순서 데이터를 이용한다. 받는 곳(서버)에서 데이터를 순서대로 다시 조립할수 있게 해준다. 그리고 순서 데이터로 빠진 데이터가 있는지도 알수 있기때문에 만약에 누락된 데이터가 있다면 이를 이용해 클라이언트에 다시 요청하는 프로세스가 쉽게 이루어진다.

포트 번호

목적지 컴퓨터의 어떤 프로그램으로 가야하는지에 대한 정보이다. 소켓은 송신자 IP, 송신자 포트번호,수신자 IP, 수신자 포트번호 로 구성된다. 포트번호가 있어야 소켓에 전송가능하다.

확인 응답 데이터

수신측에서 데이터를 받았다고 송신측에 메시지를 보냄으로써 안정성을 확보한다. 확인 응답데이터에는 에러 체크 또한 포함된다. 이게 당연한 것 같지만, 보낸 ‘데이터를 받았음’을 응답해주지 않는 프로토콜(ex. UDP)도 많다. 그러므로 당연한 것 같아도 아주 특별한 기능이다.


IP layer

TCP layer를 지나 IP 레이어로 오게된다. TCP에서 받은 데이터에 출발지/목적지 IP가 붙여진다. 인터넷 네트워크는 복잡하게 구성되어있기 때문에 여러 IP들을 거쳐서 목적지 IP로 도착하게 해주는 역할을 한다.

IP layer에는 목적지로 가기 위한 다음 IP를 알수 있는 Routing table이 존재한다. 이를 이용하여 목적지 IP로 가기 위한 다음 환승역을 찾는다.


이 부분은 대부분 물리적인 것과 관련돼있다. MAC 주소와 NIC가 핵심이다.

MAC 주소

우리가 이용하는 개별 컴퓨터는 MAC 주소라는게 있는데 이 값은 컴퓨터마다 유니크하다. 여러대의 컴퓨터는 같은 IP를 공유하게 되므로 IP만으로 목적지가 어디인지 정확히 알수 없다. 은마아파트 101동이라는 정보만으로 친구 집의 위치를 알수 없는 것처럼말이다. IP가 “은마아파트 101동”이라면 “1203호”는 MAC주소이다.

MAC주소가 덧붙여진 뒤 NIC로 전달한다. NIC에서는 데이터를 인터넷 네트워크 선에서 이동가능한 bit들로 변환한다. 그리고 최종적으로 인터넷선으로 전달한다.


서버에서 데이터 도착한 뒤

TCP/IP 스택에서 붙여진 여러가지 데이터를 이용해서 목적지 서버에 데이터가 잘 도착했다. 도착한 곳은 서버의 NIC이다. NIC에 도착하면 제일 먼저 NIC Buffer에 임시로 데이터가 저장된다. 그리고 NIC에서 Interrupt를 일으켜 운영체제에 새로운 데이터가 왔음을 알린다. 이 알림을 받은 TCP/IP 스택에서 데이터를 가져간다. 그리고 TCP/IP 작업을 거꾸로 수행한다. 클라이언트에서는 여러 데이터들을 덧붙이는 방식으로 TCP/IP 스택이 작동했다면, 서버측에서는 그 데이터를 떼어내며 작동한다. 떼어낸 데이터들은 서버 프로그램에 도착하는데 이용된다. 여러 작업을 마친 뒤 TCP layer에서 port번호까지 맞는지 확인됐다면 TCP layer와 서버 프로그램의 연결지점인 Socket에 데이터를 보낸다. 소켓 파일에 저장되는 것이 아니라 소켓의 구조체중 하나인 Receive socket buffer에 데이터가 쌓이게 된다. Receive socket buffer에 쌓인 데이터는 이제 운영체제의 책임에서 벗어났다. 이제부터는 Node.js 서버가 행동을 할 차례이다.

Node.js 서버 뿐만 아니라 대부분의 프로그램은 TCP layer와 서버 프로그램의 연결지점인 socket에 데이터가 임시로 저장된 뒤 개별 프로그램에서 데이터를 가져와 처리한다.

계층별로 정보가 덧붙여진 데이터를 부르는 명칭이 있다.
TCP -> 세그먼트 / IP -> 패킷 / Data link -> 프레임 / NIC -> 비트
(관련된 글을 처음 읽는 사람도 있을 까봐 명칭을 쓰지않고 작성한 글이다.)


프로그램이 데이터를 가져와 처리하는 방식은 다음글에서.