본 포스트는 아래 영상을 요약한 글로 원작자의 허락을 받고 올립니다. 저작권 문제시 본 글은 삭제조치하겠습니다

https://www.youtube.com/watch?v=1QiOXWEbqYQ&t=1s 

 


로그인? 아이디랑 비번 DB에 갖고있다가 로그인할 때는 그게 DB에 있는지 조회하면 될 줄 알았지만 그건 너무 날먹이었고~ㅋㅋㅋ 보안문제땜에 당연히 그렇게 안 한다고 한다.

 

로그인 기능을 만들기도 쉽지 않지만, 더 까다로운 건 로그인 상태를 유지하는 것! 지메일에 로그인했는데 메일 열 때마다 뭐 할때마다 로그인할 수는 없다. 내가 로그인하면 로그인했다는 걸 서버가 계속 알고 있어야 한다. 인증(Authentication)과 인가(Authorization)의 차이가 중요한 것.

 

JWT는 인가 즉 Authorization에 관련된 기술로, 어떤 사이트나 서비스에 사용자가 로그인했다가 서버에 인지시키는 것과 관련된다.

 

인가란 분야에서 전통적으로 많이 사용된 건 세션(session)이다. 사용자가 로그인에 성공하면 서버는 세션표딱지를 출력하는데 이걸 쭉 찢어서 반쪽은 브라우저라 보내고 반쪽은 자기가 갖는다. 브라우저는 이를 session ID라는 이름의 쿠키로 저장한다! 브라우저는 그럼 로그인된 사이트에 요청을 보낼따마다 이 표딱지를 실어보내고, 서버는 요청에 표딱지반쪽이(즉 session ID가) 서버는 자신이 가진 표딱지들 중 브라우저로부터 받은 반쪽짜리와 맞는 표딱지가 있는지 보고 ‘인가’한다. 이렇게 session ID를 사용해 서버에 로그인되어있음이 지속되는 상태를 ‘세션’이라고 표현한다. 그러나 이는 서버쪽 메모리가 날아가거나(재부팅 등으로) 너무 많은 유저들이 로그인하면 여러 반쪽표딱지들을 갖고 있어서 메모리가 부족해지는 현상이 생기기도 한다. 또한 여러 서버를 운영할 경우 로드밸런싱 문제로 로그인은 A 서버에서 하고(반쪽표딱지가 A 서버 메모리에 저장됨) 인가는 B 서버에서 진행될 수도 있는데, B 서버에는 A 서버에서 로그인한 반쪽표딱지가 없으니 에러가 생기기도 한다..

 

그래서 이런 부담없이 고안된 인가 방식이 토큰 방식인 JWT다. JSON WEB TOKEN의 줄임말이다. 토큰방식은 로그인하면 토큰이랑 딱지를 주는데, 세션방식과는 달리 반으로 찢지 않고 그대로 준다. 이는 서버가 뭔가를 기억하지 않는다는 얘기다! 토큰은 알파벳과 숫자들이 마구잡이로 섞인 문자열로 인코딩 또는 암호화된 3가지 데이터를 이어붙인 거다. XXXXXX.YYYYYY.ZZZZZZ같은 형태이며 마침표를 기준으로 세 가지 부분(헤더, 페이로드, 서명)으로 구분한다.

Payload

디코딩하면 JSON형식으로 여러 정보들이 들어있다. 토큰을 누가 누구에게 발급했는지, 언제까지 유효한지 등..토큰에 담긴 사용자 정보 등의 데이터를 Claim이라고 한다. 이를 통해 로그인 이후 요청들마다 사용자로부터 서버로 이 Claim들이 전해지는데, 사용자가 발급받아 갖고 있는 토큰 자체에 이런 정보들이 들어있으면 서버는 요청마다 하나하나 DB에서 뒤질 필요가 없으니 더 편하다. 근데 디코딩이 매우 쉬워서 누군가 수정할 오류가 있다! 근데 조금이라도 바뀌면 금방 알아챌 수 있다. 어떻게 하는지는 다음에 계속 서술

Header

디코딩하면 type(언제나 JWT가 들어감)과 alg(알고리즘)정보가 나온다. 여기는 ‘3번 서명값’을 만드는데 사용될 알고리즘이 지정된다(ex : HS256)

즉, Header와 Payload 그리고 서버에 감춰둔 비밀 값 이라는 3가지 요소를 암호화 알고리즘에 넣고 돌리면 3번 서명값이 나오는 거다. 암호화 알고리즘은 한쪽 방향으로만 계산이 돼서 토큰을 탈취해서 염병을 해도 서버가 감춰둔 비밀 값을 알아낼 수 없다.

여기서 주목. 서버는 요청에 토큰 값이 실려오면 Header와 Payload를 서버가 감춘 비밀값과 함께 알고리즘을 돌려서 계산된 값이 3번 서명값과 같다면, 그리고 유효기간이 지나지 않았다면 인가처리를 해준다. 이것이 JWT다. 참고로 Payload가 조금이라도 바뀌면 알고리즘 돌려서 나오는 값이 완전히 달라져서 3번 서명값과 같아지지 않는다. 이를 통해 payload변조를 알아챌 수 있다.

이를 통해, 서버는 사용자들의 상태를 어디다가 기록해둘 필요 없이 자신의 비밀 값만 가지고 있다면 요청들 들어올 때마다 헤비한 작업을 할 필요가 없다. 이처럼 시간에 따라 바뀌는 어떠한 상태값을 갖지 않는 걸 stateless하다고 표현한다. 세션은 반대로 stateful하다고 표현할 수 있다

그러나 JWT의 결점

stateful방식 즉 모든 사용자들의 상태를 기억하는 건 구현이 어렵고 고려사항도 많지만 구현만 되면 기억하는 대상의 상태들을 언제든 제어가능하다. 예를 들어 한 기기에서만 로그인가능한 서비스를 만든다고 하자. PC에서 로그인한 상태의 어떤 유저가 핸드폰으로 또 로그인하려하면 PC에서는 로그아웃되도록 만들 수도 있다는 얘기! JWT는 이런게 불가능하다. 이미 줘버린 토큰을 뺏을 수도 없고 토큰의 발급 내역(payload에 저장되는 정보)를 서버가 따로 추적할 수도 없으니..

즉 JWT는 내가 쥐고 있을 필요가 없어 편하긴 한데 그만큼 통제를 못 하는 방식이다.

또한 토큰이 만약 탈취된다면, 이 토큰을 무효화할 방법이 없다는 것도 큰 단점이다ㅋㅋ. 때문에 토큰을 두 개 발급하는 방법이 쓰이곤 한다. 완벽한 해결책은 아님. 이런 문제들이 큰 이슈가 안되는 서비스들에 한해서만 JWT만을 쓰는 인가방식을 쓰는 게 좋다.

코드를 짤 때 예를 들어 user의 최대 인원이 10명이라고 하면 그 인원이 쓰이는 곳에 전부다 10이란 숫자를 때려받는 방법이 있다. 이렇게 데이터를 직접 코드에 때려박는 걸 하드코딩이라고 표현한다. 이 방식의 문제점은, 만약 user의 최대인원이 20명으로 늘어나면 하드코딩된 곳 하나하나를 찾아 20으로 바꿔줘야 한다. 그러나 MAX_USER라는 변수를 사용한다면, MAX_USER의 값을 바꿔주는 것 하나만으로 방금 전 겪을 뻔한 뻘짓들을 안 할 수 있게 된다.

 

CSS에서도 여러 가지 컴포넌트에 공통적으로 들어가는 css값들이 있다. rgb방식으로 표현하는 특정 컬러라던지..이런 것들을 하나하나 직접 하드코딩하기 싫다면, CSS에서도 변수같이 쓸 수 있는 기능이 있다. 그 방법을 소개한다.

 


:root 가상클래스를 활용해 'CSS변수'를 다룰 수 있다.

 

CSS세계에서 가상클래스란 id선택자(#)나 클래스선택자(.)로 집어낼 수 없는 요소들을 선택하는 선택자로, 요소의 속성값, 상태, 상대적인 위치등을 이용해 특정 요소를 집어낼 수 있다. 

ex) :hover, :active, :nth-child(n) ...

 

이 때 :root 가상 클래스는 문서 트리의 루트 요소를 선택하는데 HTML의 루트 요소는 <html>이므로 :root로 집어낸 놈은 <html>과 같다. 단 가상클래스 선택자의 우선순위가 태그 선택자의 우선순위보다 더 높다. 이를 통해 :root로 최상위 요소에 변수를 선언하면 모든 요소에서 이 변수를 쓸 수 있는 것.

 

문서에서 공통으로 사용될 속성을 미리 변수에 선언하는 것이라 보면 된다. 하이픈(-) 두개를 통해 속성이름을 지정하고, 콜론뒤에 값을 지정하면 된다. 마치 key-value처럼..

 

 

사용할 때는 var로 변수를 선언하고 소괄호 안에 속에 key값을 입력하면 된다.

 

터미널에 다음 명령어 입력

yarn add @fortawesome/fontawesome-free

기존에 HTML에서 쓰던 것처럼(<i class="fas 뭐시기 등등")  하고 싶은 경우는 index.js에서 다음과 같이 작성해준다.

import '@fortawesome/fontawesome-free/js/all.js';

그리고 폰트어썸에서 쓰고 싶은 거 카피해서 그대로 쓰면 됨. 단 class속성은 JSX문법답게 className으로 바꿔서 쓸 것

 

아니면 리액트답게 쓰는 방법?으로 컴포넌트 형식으로 폰트어썸을 사용할 수도 있음. 사용하고자 하는 jsx파일에서

import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';

위 코드를 입력해준 후,

const Component = (props) => {
  return <FontAwesomeIcon icon={faHome} />
};

이런 식으로 쓰면 된다.

 

패키지 매니저를 yarn이 아니라 npm등을 쓸 경우는 yarn add 대신 npm install등으로 대체하면 됨

  일반적으로 서비스를 요청하는 측을 클라이언트, 제공하는 측을 서버라고 한다. 웹 브라우저, 메일 프로그램 등은 사용지 측에서 사용하는 클라이언트 애플리케이션이고, 웹 서버 프로그램이나 메일 서버 프로그램 등은 서버 측에서 쓰는 서버 애플리케이션이라 볼 수 있다. 이러한 애플리케이션은 모두 응용 계층(application layer)에서 동작한다.

 

  물리 계층, 데이터링크 계층, 네트워크 계층, 전송 계층을 통해 상대방에게 데이터를 정확하게 전달할 수 있다는 것을 알게 됐다. 응용 계층은 애플리케이션과 데이터를 주고받기 위해 필요한 부분으로, 클라이언트의 요청(request)를 전달하기 위해 통신 대상(서버 등)이 이해할 수 있는 메세지(데이터)로 변환하고 이를 전송 계층으로 전달하는 역할을 한다. 웹 브라우저, 메일 프로그램 등과 같은 클라이언트 측 애플리케이션이 서버 측 애플리케이션과 통신하려면 응용 계층의 프로토콜을 사용해야 한다. 웹 사이트를 볼 땐 HTTP, 파일을 전송할 땐 FTP, 메일을 보낼 땐 SMTP, 메일을 받을 때는 POP3라는 프로토콜을 사용한다. 암튼 결국, 응용 계층은 각각의 애플리케이션에 대응되는 데이터를 전송 계층으로 전달하는 역할을 한다. 

 

HTTP란?

  클라이언트(웹 브라우저)는 웹 사이트를 보기 위해 서버(웹 서버 프로그램)의 80번 포트를 사용해 HTTP통신을 한다. 클라이언트 측에서 HTTP request를 보내고, 서버 측에서 HTTP response를 반환하는 식이다. 지금은 HTTP/2나 HTTP/1.1버전을 사용하지만 옛날에 쓰던 HTTP/1.0버전에서는 요청을 보낼 때마다 연결했다가 응답이 오면 연결을 끊고, 요청을 또 보내게 되면 새롭게 연결하는 방식을 사용했으나 HTTP/1.1버전부터는 keepalive라는 기능이 추가되면서 연결이 한 번 되면 데이터 교환을 마칠 때까지 연결을 유지하는 방식이 가능하게 됐다. HTTP/1.1버전은 요청을 보낸 순서대로 응답을 반환한다는 특징이 있어서 이전 요청을 처리하는 시간이 길어지면 다음 요청이 밀리는 단점이 있었는데. 2.0버전부터는 순서대로 응답을 반환할 필요가 없어져서 콘텐츠를 더욱 빠르게 표시할 수 있게 됐다.

 

DNS?

  특정 사이트를 보고싶으면 특정 IP주소를 통해 웹 서버에 접속해 웹 사이트를 보는게 맞다. 네이버에 가고 싶으면 주소창에 www.naver.com을 쳐서 웹사이트를 본다. ..? 뭔가 이상하지 않은가? 네이버의 IP주소가 아니라 다른 걸 입력했는데 네이버의 웹사이트를 보고 있는 셈이니 말이다. 이것이 DNS덕분이다. 간단히 말해 DNS는 URL을 IP주소로 변환하는 시스템이다. www로 시작하는 저 url대신에 실제 네이버의 IP주소를 통해서도 물론 웹 서버에 요청을 보낼 수 있지만 네이버, 다음, 구글 등의 IP주소를 하나하나 기억하는 것은 쉬운 것이 아니다. 예를 들어 뭐..친구들 전화번호 다 외우고 있는 사람 없을 것이다. 다 전화번호부에 이름으로 저장해서 그 이름에 전화걸지..일일이 전화번호 외워서 전화거는 사람은 별로 없을 거란 얘기. DNS는 즉 일종의 전화번호부라고 생각할 수도 있겠다. 아무튼 특정 url을 사용해 웹 서버에 접속하도록 돕는 것을 DNS의 이름 해석이라고 말하며, 이는 내가 원하는 url의 IP주소를 알려주는 것을 의미한다. url을 입력하면 컴퓨터가 먼저 DNS서버에게 이 url의 IP주소를 알려달라고 요청하고, DNS서버는 컴퓨터에게 그 url의 IP주소를 반환한다. 이를 이용해 그 IP주소로 접속할 수 있는 것.

 

메일 서버의 구조

  메일을 송수신하기 위해서는 클라이언트 측의 메일 프로그램과 서버 측의 메일 서버 프로그램 간에 통신을 해야 한다. 이 때 사용되는 프로토콜의 종류에는 두 가지가 있는데 첫째는 메일을 보내는데 사용되는 SMTP고 둘째는 메일을 받는데 사용되는 POP3다. SMTP는 포트번호로 25번을, POP3는 포트 번호로 110번을 사용한다. 좀 더 정확히 설명하자면 컴퓨터 A, B와 메일 서버1, 메일 서버 2가 있을 때 SMTP를 이용해 A에서 메일서버1로 메일을 보내고, 마찬가지로 SMTP를 이용해 메일서버1에서 메일서버2로 메일을 보낸다음 POP3를 이용해 메일서버2에서 B로 메일을 보낸다. 

 

SMTP에 의한 메일 송신

  다음과 같은 순서로 진행된다

 

1) 세션 시작 통지

2) 송신자의 메일 주소 통지

3) 목적지 메일 주소 통지

4) 메일 본문 전송 통지

5) 메일 본문 송신

6) 세션 종료 통지

 

각 과정마다 응답을 받은 후 다음 과정이 진행되는 식. 방금 살펴본 것이 컴퓨터 A에서 메일서버1로 보내는 과정이었고, 메일서버1에서도 SMTP를 이용해 메일 서버2로 메일을 보낸다.

 

POP3에 의한 메일 수신

  메일 서버에는 메일 박스라고 불리는 메일을 보관해 주는 기능이 있다. 메일 서버2는 POP3를 사용해 메일 서버2의 메일박스에서 메일을 가져와 컴퓨터 B로 전송한다. B입장에서 메일 서버2로부터 메일을 수신할 때는 사용자 이름과 비밀번호를 이용한 사용자 인증이 필요하다. POP3 프로토콜로 110번 포트를 사용한다. POP3는 다음과 같은 순서로 진행된다. B가 메일서버2에게

 

1) 세션 시작 통지 -> 메일서버2가 확인응답 보냄

2) 수신자의 사용자이름 통지 -> 메일서버2가 확인응답 보냄

3) 수신자의 비밀번호 통지  -> 메일서버2가 확인응답 보냄

4) 메일을 확인  -> 메일서버2가 "있음"이라는 확인응답 보냄

5) 메일의 전송 요청 -> 메일서버2가 메일내용 전송

6) 세션 종료 요청

  네트워크 계층을 설명할 때 다른 네트워크로 데이터를 전송하려면 라우터가 필요하고, 라우터의 라우팅 기능을 사용해 전송할 수 있다고 했다. 문제는 이렇게 데이터를 전송하더라고 목적지에 잘 도착하지 않을 수도 있다는 것! 우리가 편지를 보낼 때도 예기치 못한 사고로 인해 배송이 지연되거나 중간에 분실되거나 할 수 있는 것처럼 말이다. 물리 계층, 데이터 링크 계층, 네트워크 계층을 통해서 목적지에 데이터를 보낼 수는 있지만, 배송 과정에서 데이터가 손상되거나 유실되더라도 이들은 아무것도 해주지 않는다 즉 책임을 지지 않는다. 참으로 괘씸하기 짝이 없다.  이 때 전송 계층(transport layer)는 목적지에 신뢰할 수 있는 데이터를 전달하기 위해 필요한 계층으로, 오류를 점검하는 기능이 있다! 이를 통해 오류가 발생하면 데이터의 재전송을 요청하기도 한다. 다시 말하면 네트워크 계층이 목적지까지 데이터를 전달하는 역할을 한다면 전송 계층에서는 데이터가 제대로 잘 갔는지 확인하는 역할을 하는 것이다. 

  

  전송 계층은 오류 점검말고도 한 가지 역할을 더 수행한다. 건물로 편지를 잘 보냈지만 그 건물 어느 호실에 편지를 전해야 할 지 모른다면 어떠겠는가? 마찬가지로 컴퓨터가 데이터를 받아도 어떤 애플리케이션에 전달해야 하는지 모른다면 곤란하게 된다. 전송계층에서는 전송된 데이터의 목적지가 어떤 애플리케이션인지 식별하는 역할 역시 수행한다.

 

  전송 계층의 특징을 간단히 설명하면 신뢰성/정확성효율성으로 구분할 수 있다. 신뢰성/정확성은 데이터를 목적지에 문제없이 전달하는 것을, 효율성은 데이터를 빠르고 효율적으로 전달하는 것을 의미한다. 이 때 신뢰할 수 있고 정확한 데이터를 전달하는 통신을 연결형 통신이라고 하고, 효율적으로 데이터를 전달하는 것을 비연결형 통신이라고 한다. 좀 더 설명하자면 연결형 통신은 상대편(수신자)와 하나하나 확인하면서 데이터를 전송하는 방식이고, 비연결형 통신은 일방적으로 데이터를 전송하는 방식이다.

 

ex) 연결형 통신

A : 보내도 돼?

B : 네, 보내세요

A : 보냅니다!

B : 받았슴다~!

A  : 확인~

 

ex) 비연결형 통신A : 보낸다~수고~

 

이는 당연한 얘기지만 연결형 통신은 신뢰성/정확성을 우선으로 하는 통신이고, 비연결형 통신은 효율성을 우선으로 하는 통신방식이기 때문에 그렇다. 그럼 여기서 궁금한 점이 생길 수 있다. 신뢰성과 정확성이 보장되지 않는 저 상도덕 없이 일방적으로만 보내는 비연결형통신을 사용하는 경우가 있는가? 정답은 당연히 Yes, 예를 들면 동영상을 시청할 때다. 동영상은 아무래도 빠른 전송이 필요하기 때문! 정확하게 하나하나 확인하면서 한다고 하면 데이터가 늦게 도착해 화면이 버벅거리는 영상을 보게 될텐데, 그것보다는 좀 유실되더라도 원활하게 보는 것이 낫기 때문이다. 이 연결형 통신의 프로토콜로는 그 유명한 TCP가 쓰이고, 비연결형 통신 프로토콜로는 UDP가 사용된다.

 

 

TCP의 구조 [1] 3-way handskake

  다른 계층과 마찬가지로 전송계층에서 TCP프로토콜로 데이터를 전송할 때도 데이터에 TCP헤더를 붙여서 덩어리를 만들어 보내며, 이 덩어리를 세그먼트라고 한다. 이 TCP헤더에는 출발지 포트 번호, 목적지 포트 번호, 일련번호, 확인 응답 번호..등과 같은 다양한 정보들이 담긴다. 앞서 말했듯 TCP는 꼼꼼하게 상대방을 확인하면서 데이터를 보내는 연결형 통신이기 때문에 사실 데이터를 전송하기 전에 해야 하는 작업이 있다. 그건 바로 데이터를 전송하기 위해 연결(connection)이라는 가상의 우리 둘만의♡(즉 독점적인) 통신로를 확보하는 것이다. 이 연결을 확보한 후에 데이터를 전송할 수 있다.

 

  이 연결을 그럼 어떻게 확보하는가? TCP헤더를 보면 107 ~ 112비트까지의 총 6비트로 구성된 '코드 비트'라는 정보가 있다. 이 코드 비트에 연결의 제어 정보가 기록되는데, 6개 비트가 각 비트별로 역할이 있다. 6개 각 비트들에는 URG, ACK등 각각을 칭하는 이름이 있으며 이들의 초깃값은 0이고 활성화되면 1이 된다. 이 때 우리가 원하는 '연결'을 확보하려면 이 중 SYNACK가 필요하다. SYN은 연결 요청, ACK는 확인 응답을 뜻한다. 이 두 녀석을 활용해 '연결'은 다음과 같이 3-way handshake로 확립된다.

 

ex)컴퓨터 A, B가 있고 A가 B랑 연결을 확보하고 싶은 상황.

 

1) A가 먼저 B에게 허가를 받아야 하므로 연결 확보 허가를 받기 위한 요청(SYN)을 보낸다2) B는 A가 보낸 요청을 받은 후 허가한다는 응답을 회신하기 위해 ACK를 A에게 보낸다. 이와 함께 B 역시 A에게 데이터 전송 허가를 받기 위해 연결 확보 허가를 받기 위한 요청(SYN)을 보낸다.3) B의 요청을 받은 A는 허가한다는 응답(ACK)를 B에게 보낸다.

 

그림으로 나타내면 다음과 같다.

데이터를 보내기 전에 연결을 확보하기 위해 패킷 요청을 총 3번 교환하므로 3-way handshake라고 부른다. 네트워크 분야에서 이 핸드셰이크(handshake)는 사람들이 상대방을 확인하고 악수하는 것처럼 데이터 통신에서도 확실하게 데이터가 전송됐는지 확인하며 이루어지는 통신 수단을 말한다. 데이터를 다 전송한 후엔(서로 볼 일 다 봤을 땐) 바로 손절하는게 아니라 젠틀하게 연결을 끊기 위한 요청을 교환하는데, 이 때는 FIN과 ACK를 사용한다.

 

TCP의 구조 [2] 일련번호와 확인 응답 번호의 구조

  3-way handshake를 했다면 이제 데이터 전송을 해야 된다. 데이터 전송을 할 땐 이 땐 TCP헤더에서 일련번호와 확인응답번호가 쓰인다(둘 다 32비트). TCP는 데이터를 분할해서 보내게 되는데 일련번호는 순서를 가진 연속된 번호로 송신측에서 수신측에게 "이 데이터가 몇 번째 데이터야"라고 알려줄 때 쓰인다. 이를 통해 수신자는 이 데이터가 원래 데이터의 몇 번째 데이터인지 알 수 있다. 확인 응답 번호는 수신자가 송신자에게 몇 번째 데이터를 수신했는지 알려줄 때 쓰이는 번호로, 10번 데이터를 받았다면 송신자에세 확인 응답 번호로 11번을 보낸다. 뭐 굳이 뜻을 붙이자면 "저는 10번 데이터를 받았으니, 그 다음 번호인 11번을 주시면 됩니다" 하는 것이다. 이 작업을 '확인 응답'이라고 부른다.

 

  좀 더 구체적으로 설명하자면, 일련번호는 내가 보내는 데이터의 첫 번째 바이트 번호이다. 3001번 ~ 3200번까지의 200바이트짜리 데이터를 보낸다고 하면 일련번호는 3001이 되는 것. 이를 받는 쪽은 3001 ~ 3200번까지의 200바이트 데이터를 받았으니 다음엔 3201번부터 받을 차례이므로 확인 응답 번호로 3201을 보낸다. 이를 통해 내가 보낸 데이터가 잘 갔는지 확인이 가능하다. 데이터가 항상 올바르게 전달되는 것은 아니므로 일련 번호와 확인 응답 번호를 사용해 데이터가 손상되거나 유실된 경우가 확인되면 데이터를 재전송할 수 있는 것! 이를 재전송 제어라고 한다.

 

  이때까지 설명한 것은 세그먼트 하나를 보낼 때마다 확인 응답을 한 번 반환하는 통신이었다. 그러나 이 방법은 당연히 효율이 좋지 않다. 애시당초 연결형 통신 자체가 신뢰성/정확성을 우선시하는 통신이긴 하지만 그럼에도 불구하고 너무나도 극악의 효율이라는 것이다. 그러나 매번 하나 보내고 확인 응답 기다리고..를 반복하는 것보단 세그먼트를 연속해서 촤라락 보내고 난 다음에 확인 응답을 반환한다면 어떨까? 효율이 더 높아질 것이다! 그러나 이 경우 상대방 쪽에선 세그먼트가 점점 쌓일 것이라는 문제를 제기할 수 있는데, 받은 세그먼트를 일시적으로 보관할 수 있는 장소인 버퍼(buffer)가 있어서 괜찮다. 이 버퍼 덕분에 송신자 측에서 세그먼트를 연달아 보내도 수신 측은 대응이 가능하고 확인 응답의 효율이 높아진다. 

 

  그러나 버퍼의 크기는 정해져있기 마련이므로 너무 대량의 세그먼트를 받으면 처리하지 못하는 경우도 생긴다. 버퍼가 넘치게 되는 현상을 오버플로(overflow)라고 부르며, 이 오버플로가 발생하지 않도록 버퍼의 한계 크기를 알고 있어야 한다. 이것이 TCP헤더의 윈도우 크기 정보에 해당하는 부분이다. 윈도우 크기는 버퍼가 얼마나 많은 용량의 데이터를 저장해 둘 수 있는지에 대한, 즉 확인 응답을 일일이 하지 않고 연속해서 송수신 가능한 데이터 크기를 말한다. 이 윈도우 크기의 초깃값은 3-way handshake를 할 때 판단하며, 보내는 쪽의 윈도우 크기를 담아서 보내게 된다. 

 

ex) 컴퓨터 A가 B에게 SYN을 보낼 때 자신의 윈도우 크기를 담아서 보내고, B는 이를 통해 A의 윈도우 크기가 몇이구나를 알게 됨

 

이렇게 상대방의 윈도우 크기를 알게 됐다면 상대방 버퍼의 한계치를 알게 된 것이니, 세그먼트를 오버플로되지 않도록 보내면 되는 것!

 

TCP의 구조 [3] 포트 번호의 구조

  지금까지 연결 확보, 재전송 제어, 윈도우 크기에 대해 알아봤고 이들을 통해 TCP는 정확한 데이터 전송이 가능했다. 앞서 설명했듯 TCP는 이것 말고도 한 가지 역할을 더 하는데, 그건 바로 수신한 데이터가 어떤 애플리케이션에 가야 하는지 구분하는 역할이었다. 이를 위해 TCP헤더에는 출발지 포트 번호와 목적지 포트 번호에 대한 정보가 있고, 이를 통해 어떤 애플리케이션으로 가야 하는지 구분할 수 있다. 둘 다 16비트를 갖는  녀석으로 0 ~ 65535번까지의 포트번호를 쓸 수 있다고 생각할 수 있지만, 0 ~ 1023번 포트는 주요 프르토콜이 사용하도록 예약된 포트이다. 1024번은 예약되어 있지만 안 쓰는 포트고, 1025번 이상부터 랜덤 포트라고 부르며 클라이언트 측의 손싱 포트로 사용된다. 0 ~ 1023번 포트는 주로 서버 측 애플리케이션에서 사용된다.

 

  아무튼, 컴퓨터 상에서 애플리케이션들은 각각 포트 번호가 있어서 다른 애플리케이션과 구분되며, 데이터를 전송할 땐 상대방의 IP주소가 필요하지만 어떤 애플리케이션에게 줄 지를 결정하기 위해서 TCP는 꼭 포트 번호가 필요하다. 즉 일종의 창구 역할을 하는 것이 포트라고 생각할 수 있는 것. 

 

 

UDP의 구조

  UDP는 비연결형 통신이기 때문에 데이터를 전송할 때 TCP처럼 시간이 걸리는 확인 작업을 일일이 하지 않는다. 왜 why? 얘는 효율성을 더 우선시하는 통신방법이니까. 때문에 UDP의 장점은 데이터를 효율적으로 빠르게 보내는 것에 있기 때문에.

  

  TCP에서는 TCP헤더를 붙인 덩어리를 세그먼트라고 불렀던 반면 UDP는 UDP헤더를 붙인 덩어리를 UDP 데이터그램이라고 부른다. 이 녀석도 출발지 포트 번호, 목적지 포트 번호 등의 정보를 가진다. TCP와의 또 한 가지 차이점은 TCP는 번거롭게 여러 번 확인 응답을 보내며 전송하던 반면 UDP는 상대방을 확인하지 않고 연속해서 데이터를 보낸다! 즉 확인 응답 하지 않고 A쪽에서 B쪽으로 와다다다 데이터를 보내기만 하는 구조이다. 또한 UDP를 사용하면 랜에 있는 컴퓨터나 네트워크 장비에 데이터를 일괄로 보낼 수 있는데 이를 브로드캐스트(broadcast)라고 한다.

 

 

지금까지 전송계층에 대해 얘기했다. 다시 한 번 정리하자면, 전송 계층은 신뢰할 수 있는 데이터를 순차적으로 전달하는 역할을 하므로 상위 계층들이 데이터 전달의 유효성 등을(잘 전달됐을까..?) 신경스지 않도록 만들어준다! 상사한테 "신경쓰지 마십쇼. 제 선에서 처리하겠슴다"하면서 자기가 일일이 확인해주는 녀석.

 

 

  

+ Recent posts