이 포스트는 널널한 개발자님 강의를 참조하여 작성한 포스트입니다.
인터넷이라는 환경에서 가장 중요한 L4프로토콜이 TCP와 UDP이다. 이것을 공부해보면 너무 할께 많다. 특히 TCP는 정말 복잡하다. TCP와 UDP 애기를 할 때 연결지향이냐 아니냐에 이야기를 한다. TCP의 연관검색어가 연결일 정도로 TCP는 연결이라는 개념이 존재하고 필요하며, UDP는 연결이라는 개념이 존재하지 않는다.
그런데 연결이라는 단어는 우리말로 번역했을 때 그런거고 영문표기상 2가지 단어가 혼재하는데 Connection과 Session이 존재한다. 예를 들어 TCP 연결이라고 우리말로 번역한것을 영문표기에는 TCP Connection 혹은 TCP Session이라고도 하며 연결이 논리적 개념이라고 말하는 것처럼 논리적은 Virtual로 바꿔말하기도 해서 Virtual Circuit이라고도 표기한다.
TCP연결이라는 것은 순서번호 개념이 존재한다. TCP Segment를 퍼즐 1조각에 비유한 다음에 이 조각들에게 순서번호를 붙이는 것과 같다. 이 번호는 Segment의 사이즈의 byte 수만큼 증가를 한다. 예를 들어 1번째 조각 번호가 1이고 이 조각의 byte수가 400byte이면 2번째 조각의 번호는 401이 된다. 그래서 이 Segment 순서번호를 보고 송수신 양을 측정하기도 한다.
'연결'이라는 말이 항상 따라다니는 용어가 '상태'라는 말이다. 또한 상태는 전이가 된다. 예를 들어 전화를 생각해보자. 누군가한테 전화를 걸려한다면 전화번호를 누르는 전화를 걸기 전 상택라 있을 것이고 통화음이 들리는 통화 전 상태가 있고 통화 상태, 통화를 끊는 상태가 있다. 이것은 연결 전, 연결, 연결 후, 연결이 끊긴 상태로 볼 수 있을 것이고 이런 식으로 TCP의 연결을 전화통화로 비유하면 이해가 조금은 될 것이다.
또한 TCP는 배려남, UDP는 나쁜남자로 비유할 수 있는데 왜그러냐면 TCP는 데이터를 보낼 때 수신측에 여유공간이 없다면 zero-window라는 장애상황을 고려해 데이터를 보내지 않은데, UDP는 수신측에 여유공간이 있든 없든간에 데이터를 보낸다.
복습겸 이전에 배웠던 내용부터 확인해보자. OSI 7 Layer의 식별자부터 확인해보자. L2 식별자는 MAC Address이고 L3는 IP주소, L4는 port번호이다. 그러니까 port번호라는 것을 끄집어내서 뭔가를 논한다는 것은 L4수준까지의 애기이다. 데이터 단위를 애기해보면 L2 데이터 단위는 Frame, L3는 Packet, L4는 Segment or Datagram, L5~L7에서는 socket이란 놈이 등장하는데 이때는 시작은 있는데 끝을 모르는 Stream으로 표현하고 이 끝은 socket 통신을 하는 process가 정하는 Application protocol이 규정에 따른다.
TCP, UDP 통신하는 경우를 조금 자세히 설명하면 TCP는 기본적으로 client와 server로 구성이 된다. client는 active하게 연결을 하는 주체이고 server는 기다리고 연결을 받는다. 클라이언트와 서버 둘다 소켓 인터페이스를 열고 서버측에서 누군가 이 서버에 접속할텐데 서버는 이를 위해 연결대기상태를 하고 있다. 클라이언트 측에서 프로세스가 소켓을 open하면 OS입장에서 이 소켓에다가 TCP port번호를 부여한다. 이 때 번호는 OS에서 남는 번호를 준다. 예를 들어 클라이언트측 IP주소가 192.168.0.10이고 포트가 3000번을 열었고 서버측 192.168.0.20이면 192.168.0.10:3000으로 192.168.0.20에 접속하는거다. 만약 서버가 웹서버면 서버측 port는 80을 쓴다.
그래서 연결대기하는측에서 서버측 프로세스로 소켓 생성 및 개방을 하는데 이때 소켓이 listen 상태가 된다. 그리고 서버는 연결대기를 하는데 프로세스가 OS한테 80번 포트를 써도 되는지 여부를 확인하고 써도 되면 연결대기를 하고 아니면 연결거부가 된다.
그래서 TCP통신을 하려면 상대측 IP + port번호를 알아야 연결이라는 것을 시도해볼 수 있다. 만약에 연결을 하려하는데 연결중인 프로세스도 없고 소켓도 안 열려 있는데 클라이언트가 요청을 보내면 서버측은 TCP 스택에서 연결이 안되어서 거부되었다고 응답 메세지를 보낸다.