본문 바로가기
네트워크

[브라우저에 URL 입력 후 일어나는 일들] 4_TCP 소켓 통신

by 이농이능 2019. 1. 15.


지난번 포스팅에서 목적지의 IP와 MAC 주소를 찾는 것 까지 서명해보았는데요!

오늘은 데이터를 전송하기 위해 서버와 클라이언트가 TCP 프로토콜을 통해 연결하는 과정을 설명해보도록 하겠습니다.

브라우저가 목적지 서버의 IP 주소를 받으면 거기서 호스트명과 포트 번호를 뽑아내서 socket 이라는 이름의 시스템 라이브러리를 호출하고 TCP 소켓 스트림 ( AF_INET/AF_INET6 과 SOCK_STREAM )을 요청합니다.


  • 이 요청은 먼저 TCP 세그먼트가 제작되는 Transport 전송 계층으로 전달됩니다. 목적지 포트는 헤더에 더해지고, 출발지 포트는 커널의 동적 포트 범위 (리눅스의 ip_local_port_range) 에서 선택됩니다.
  • 이 세그먼트는 추가적인 IP 헤더를 덧씌우는 Network 레이어로 보내집니다. 지금의 머신뿐 아니라 목적지 서버의 IP 주소도 담아 패킷을 만들죠.
  • 패킷은 곧 Link 레이어에 도착합니다. 머신 NIC의 MAC 주소에 게이트웨이(로컬 라우터)의 MAC 주소까지 포함한 프레임 헤더가 더해지죠. 전과 마찬가지로, 커널이 게이트웨이의 MAC 주소를 모르면, ARP 쿼리를 브로드캐스트 해서 찾아야합니다.
패킷은 다음 중 하나로 전송될 준비를 마칩니다.
* 이더넷
* 와이파이
* 무선 통신 네트워크

패킷은 로컬 서브넷을 관리하는 라우터에 도착하여 목적지 서버까지 이동하게 됩니다. 이 때 지나치는 각각의 라우터는 IP 헤더로부터 목적지 주소를 추출해내서 다음 단계로 이어줍니다.

이 송수신 동작은 TCP 연결 흐름에 따라 여러 차례 일어납니다.

  • 클라이언트가 초기 순서 번호 (ISN, Initial Sequence Number) 을 선택하고, ISN을 설정하는 중임을 나타내는 SYN 비트가 set된 한 패킷을 서버로 보냅니다.
  • 서버가 SYN을 수신하고 수용가능한 상태인지 확인합니다:
    • 서버가 자신의 initial sequence number를 고릅니다
    • 서버가 ISN 선택중임을 알리는 SYN 비트를 set합니다
    • 서버가 (클라이언트 ISN + 1) 을 ACK 영역에 붙이고 첫 번째 패킷을 확인했다고 알리는 ACK 플래그를 추가합니다
  • 클라이언트가 패킷을 하나 보내 연결을 확인해줍니다:
    • 자신의 ISN을 하나 올립니다
    • 수신자 확인 번호를 하나 올립니다
    • ACK 필드를 set합니다.
  • 데이터가 다음과 같이 옮겨집니다:
    • 한 쪽에서 N개의 데이터 바이트를 보내면서, SEQ를 해당 숫자만큼 증가시킵니다
    • 반대편이 그 패킷 (혹은 연결된 여러 패킷) 을 받았다고 알리면, 상대로부터 마지막에 받았던 순서와 같은 ACK 값을 담아 ACK 패킷을 보냅니다
  • 연결을 끊을 때:
    • 닫는 쪽이 FIN 패킷을 보냅니다
    • 반대편이 FIN 패킷을 ACK하고 자신의 FIN을 보냅니다
    • 닫는 쪽이 반대편의 FIN을 ACK와 함께 확인하고 알립니다



** OSI7 네트워크 계층에서 데이터를 전송하는 부분을 담당하는 것이 바로 전송계층인데요. 전송계층은 송신자와 수신자를 연결하는 통신서비스를 제공하는 계층입니다. 

이때 데이터를 보내기 위해 사용하는 프로토콜이 있는데 그 프로토콜이 바로 TCP와 UDP 입니다.


TCP 와 UDP를 사용하려면 소켓 시스템 콜 이라는 라이브러리 함수를 이용합니다.

소켓 API는 애플리케이션층과 전송층 간의 통신 모델에 위치합니다. 

소켓 API는 애플리케이션이 통신 모델의 전송층 또는 네트워크층과 상호작용할 수 있도록 합니다.



소켓이란?

소켓 (socket) :

통신을 원하는 프로세스에 할당되는 자원이며 두 프로그램이 네트워크통해 서로 통신할 수 있는 통신 접속점이라고 할 수 있습니다. 

네트워크 응용 프로그램은 소캣을 통하여 통신망으로 데이터를 송수신합니다. 고유의 소켓 주소가 부여됩니다.

소켓은 응용 프로그램에서 TCP/IP를 이용하는 창구 역할을 하며 응용 프로그램과 소켓사이의 인터페이스를 '소켓 인터페이스'라고 합니다. 




<응용프로그램과 소켓 그리고 TCP/IP>

그림은 응용 프로그램과 소켓 그리고 TCP/IP의 관계를 구체적으로 나타냄.

▶ 네 개의 응용 프로그램이 소켓번호로 각각 4, 3, 3, 3을 사용하고 있는 것을 나타냈다(응용 프로그램 1은 파일을 하나 먼저 열고 있으므로 소켓번호가 4가 된 것이다).

▶ 한편 소켓번호는 응용 프로그램내에서 순서대로 배정되며 그 프로그램내에서만 유일하게 구분되면 되는 것이므로 서로 다른 응용 프로그램에서 같은 소켓번호를 사용하는 것은 문제가 되지 않는다.

▶ 포트번호는 TCP/IP가 지원하는 상위 계층의 프로세스를 구분하기 위한 번호이므로 하나의 컴퓨터내에 있는 응용 프로세스들은 반드시 서로 다른 포트번호를 사용하여야 한다.

▶ 그림 2-3에서는 네 개의 응용 프로그램이 3000번부터 3003번의 포트번호를 사용하는 것을 가정하였다.

▶ 그림 2-3에서 연결형 서비스는 TCP가 그리고 비연결형 서비스는 UDP가 각각 처리하는 것을 보였다.

▶ IP 주소 192.203.144.11은 이 컴퓨터에 배정된 IP 주소인데 예를들어 목적지 IP 주소가 192.203.144.11인 IP 패킷은 모두 그림 2-3의 컴퓨터로 전달된다.

▶ 이 패킷을 수신할 응용 프로그램은 TCP(또는 UDP) 헤더에 있는 16비트의 포트번호를 참조하여 구분된다



소켓의 이용


소켓을 이용한 네트워크 응용 프로그램에서 상대방과 IP 패킷을 주고받기 위해서는

1) 통신에 사용할 프로토콜 (TCP , UDP)

2) 자신의 IP 주소

3) 자신의 포트번호

4) 상대방의 IP 주소

5) 상대방의 포트번호

5가지 정보가 정해져야 합니다.


(1) 통신에 사용할 프로토콜


연결형 또는 비연결형을 말하는데 인터넷 프로그램에서는 연결형 서비스를 TCP 또는 스트림(Stream) 서비스라고 부르고 비연결형 서비스를 UDP 또는 데이터그램 서비스라고 부릅니다.


1-1) TCP 와 UDP 차이.

* UDP : 

- 비연결형 서비스로 데이터그램 방식을 제공.

- 정보를 주고 받을 때 정보를 보내거나 받는다는 신호절차를 거치지 않음.

- UDP 헤더의 CheckSum 필드를 통해 최소한의 오류만 검출.

- 신뢰성 낮음.

- TCP 보다 속도가 빠름.

특징) 파일 전송과 같은 신뢰성이 필요한 서비스보다 성능이 중요시 되는 경우 사용되어 실시간 스트리밍 서비스에 자주 사용됨.


* TCP :

- 연결형 서비스.

- 3-way-handshaking 과정 통해 연결을 설정하고 4-way handshaking 을 통해 해제.

- 흐름 제어 및 혼잡 제어.

- 높은 신뢰성을 보장.

- UDP 보다 속도가 느리다.

 특징) 연결성을 보장하기 때문에 신뢰성있는 전송이 중요할 때 사용함. 서버와 클라이언트는 1대1로 연결되며 패킷에 대한 응답을 해야하기 때문에 성능이 낮음.


(2) socket()의 사용 문법

int socket (

domain, /* 프로토콜 체계 */

type, /* 서비스 타입 */

protocol; /* 소켓에 사용될 프로토콜 */


소켓은 본래 TCP/IP, 즉 인터넷만을 위해 정의된 것이 아니라서 UNIX 네트워크, XEROX 네트워크 등에도 사용될 수 있도록 프로토콜 체계를 지정할 수 있음.

* AF_INET(Address family_internet) : 인터넷 주소 체계. IPv4프로토콜체계를 사용하겠다는 뜻.


서비스 타입은 연결형 서비스인지 비연결형 서비스인지 확인하기 위한 것.


소켓 TYPE

SOCK_STREAM :

- 연결지향형 소켓생성.

- TCP처럼 연결형 서비스를 지원하는 프로토콜을 사용할때 소켓은 연결성 소켓을 사용해야한다.


SOCK_DGRAM :

- 비연결성 소켓(Datagram socket) :

- UDP처럼 비연결형 서비스를 지원하는 프로토콜을 사용할때는 비연결성 소켓인 사용


SOCK_RAW :

- 로 소켓(Raw socket) 

- 응용프로그램에서 Layer4인 전송계층을 거치지 않고 바로 Layer3인 네트워크 계층에 어떤 명령을 내리는 소켓을 사용하고 싶을때


SOCK_PACKET :

- 패킷 소켓(packet socket) 

- 응용프로그램에서 Layer2인 데이터링크 계층(랜카드,이더넷)으로 바로 명령을 내리고 싶을때 (그사이의 계층들을 거치지 않고 바로)





소켓 통신 절차


소켓은 일반적으로 클라이언트 및 서버 상호작용에 사용됩니다. 일반적인 시스템 구성은 서버를 한 시스템에 두고 클라이언트를 다른 시스템에 둡니다. 클라이언트는 서버에 연결하여 정보를 교환한 후 연결을 끊습니다.

소켓에는 일반적인 이벤트 흐름이 있습니다. 연결 지향성 클라이언트 대 서버 모델에서는 서버 프로세스의 소켓이 클라이언트의 요청을 기다립니다. 이를 수행하기 위해 서버는 먼저 클라이언트가 서버를 찾는 데 사용할 수 있는 주소를 설정(바인드)합니다. 주소가 설정되면 서버는 클라이언트가 서비스를 요청하기를 기다립니다. 클라이언트 대 서버 데이터 교환은 클라이언트가 소켓을 통해 서버에 연결하면 이뤄집니다. 클라이언트 입장에서는 연결이 수락되면 소켓은 성공적으로 생성되며 클라이언트는 서버와 통신하기 위해 소켓을 사용할 수 있게됩니다. 클라이언트와 서버는 이제 소켓에 데이터를 쓰거나 읽음으로써 통신할 수 있게 됩니다. 서버는 클라이언트의 요청을 수행한 후 클라이언트에 응답을 송신합니다.


<연결 지향성 소켓의 일반적인 이벤트 흐름.>


1. socket() API가 통신을 위한 종료점을 작성하고 해당 종료점을 나타내는 소켓 설명자를 리턴합니다.

2. 애플리케이션은 소켓 설명자를 획득한 후 해당 소켓에 고유 이름을 바인드할 수 있습니다. 네트워크에서 액세스하기 위해서는 서버가 이름을 바인드해야 합니다.

3. listen() API가 클라이언트 연결 요청을 승인하려는 의사를 표시합니다. listen() API가 소켓에 대해 실행되면 해당 소켓은 능동적으로 연결 요청을 시작할 수 없습니다. listen() API는 socket()API를 사용하여 소켓이 할당되고 bind() API가 소켓에 이름을 바인드한 후 실행됩니다. listen()API는 accept() API가 실행되기 전에 실행되어야 합니다.

4. 클라이언트 애플리케이션이 스트림 소켓에 대해 connect() API를 사용하여 서버에 대한 연결을 설정합니다.

5. 서버 애플리케이션이 accept() API를 사용하여 클라이언트 연결 요청을 승인합니다. 서버가 accept() API를 실행하기 위해서는 먼저 bind()  listen() API를 실행 완료해야 합니다.

6. 스트림 소켓 간(클라이언트와 서버 간)에 연결이 설정되면 모든 소켓 API 데이터 전송 API를 사용할 수 있습니다. 클라이언트 및 서버에는 send(), recv(), read(), write() 등과 같이 선택할 수 있는 많은 데이터 전송 API가 있습니다.

7. 서버 또는 클라이언트는 조작을 중단하려는 경우 close() API를 실행하여 소켓이 획득한 시스템 자원을 해제합니다.



결론적으로,


목적지 서버의 주소를 알고난 후에 데이터를 보낼 때 소켓을 열고 연결형 통신 프로토콜인 TCP를 이용해서 데이터를 전송합니다.

그런데 TCP 를 통해 데이터를 통신하기 위해서는 연결이 확인 된 후 데이터를 보내야 하기 때문에 복잡한 과정을 거치게 됩니다.


이때 연결을 하기 위해서는 3-way-handshake를 이용하고 연결을 해제할 때는 4-way-handshake 를 이용하여 접속을 끊습니다.

(더 자세한 설명은 http://asfirstalways.tistory.com/356 를 참고하시길 바랍니다.)


서버는 이후에 클라이언트와 연결된 상태에서 HTTP 프로토콜을 통해 클라이언트의 요청을 받아서 응답을 해주기 위한 과정을 거치게 되는데요.


다음에는 HTTP 데이터를 전송하기 전 암호화를 하기 위한 TLS handshake 에 대해서 먼저 설명하겠습니다.