네트워크
-
Multiplexing, deMultiplexing2023.10.25
-
소켓2023.10.23
-
DNS2023.10.19
-
HTTP1/HTTP2/HTTP32023.10.19
TCP(1)
TCP
TCP 란 연결지향형 프로토콜이며, 다음과 같은 특징이 있다.
- point-to-point: 소켓과 소켓 간의 연결 (한쌍의 소켓 간의 연결이다)
- reliable, in-order byte stream : 신뢰성 및 순서 보장
- pipelined : 여러 데이터를 한번에 보낼수 있다.
- full duplex data: 송신자이자 수신자가 될수 있다.
- connection oriented : handshaking 을 연결단계에 한다.
- flow controlled: 상대방의 컴퓨터 성능에 맞춰 segment를 보낸다.
- congestion controll: 네트워크 상태에 따라 보내는 속도를 조절한다.
TCP 세그먼트 구조
위 사진은 TCP 세그먼트 구조를 나타낸다.
순서 번호 (sequence number)
순서번호는 특정 세그먼트의 첫번째 바이트 이다. 예를 들어, 첫 번째 세그먼트가 100바이트 크기를 가지고 시작 순서 번호가 0이라면, 이 세그먼트는 0번 바이트부터 99번 바이트까지의 데이터를 포함한다. 따라서 다음 세그먼트의 시작 순서 번호는 100이 된다.
확인 응답 번호 (acknowledgement number)
확인 응답 번호는 다음으로 기대하는 바이트 이다. 만약 ACK#100 이라면, 나는 sequence number 가 99 번인것까지는 모두 정상적으로 받았고 이제 sequence number가 100번인 데이터를 받기를 기대한다 라는 의미이다.
Window
TCP 연결을 하게되면 송신 수신 시스템 모두 Send Buffer 와 Rcv Buffer 를 가지게 된다.
이때 TCP 프로토콜은 애플리케이션 계층으로부터 받은 데이터를 Send Buffer에 넣은후 수신시스템인 B의 Rcv Buffer에 전송하게 된다.
애플리케이션 계층은 TCP 의 전송속도를 고려하여 소켓에 메세지를 보내지 않는다. 즉 Send Buffer엔 TCP 프로토콜에 의해 보내지는 데이터보다 더 많은 데이터가 쌓여있다.
Window란 Send Buffer에서 TCP프로토콜이 한번에 보낼수 있는 데이터의 양이다.
즉 Window의 크기가 1000byte 라면 TCP 프로토콜은 한번에 1000byte의 데이터를 TCP가 연결된 상대방에게 보낼수 있는 것이다.
TCP 커넥션에서 타이머 및 Send Buffer Rcv Buffer의 상세한 동작과정은 컴퓨터 네트워크 강의 해당 강의 38:00 부터 보면된다.
위 강의를 기반으로 TCP 연결에서의 버퍼 동작과정을 간단하게 정리를 하자면
- Send Buffer 는 결국 재전송을 위한 버퍼이다. base send에 타이머가 물려있으며, 전송해야하는 데이터에 대한 ACK 응답을 받으면 타이머를 이동시킨다.
- Rcv Buffer 는 in-order 를 위한 버퍼이다. sequence number를 기반으로 데이터가 순서에 맞춰 잘 들어 왔는지 확인한다.
- A,B 모두 데이터를 보내고 받을수 있다. 실제 TCP 동작에선 Send Buffer에서 데이터를 보낼때 해당 데이터의 헤더의acknowledgement number에 ACK 응답을 포함한다. (sequence number에는 보내는 데이터의 sequence number가 들어간다.)
Timer 한계 극복
Timer 라는건 Send Buffer의 base send(보내야하는 맨앞 데이터)를 가리키고있다.
해당 데이터에 대한 ACK응답이 도착하면 Send Buffer에서 해당 데이터를 지운다. 만약 데이터가 중간에 유실되었다고 가정해보면, Timer의 timeout 전까지는 재전송을 하지 않으며, 이는 생각보다 비효율 적이다.
Timer의 timeout은 기본적으로 평균 rtt + margin 정도의 시간을 가지는데 이는 생각보다 긴 시간이다.
이러한 문제점을 해결하기위해 fast retransmit(빠른 재전송) 을 사용한다.
위 그림과 같이 윈도우의 크기가 400바이트 이며, 각각의 segment는 100바이트라고 가정을 해보자.
이때 sequence number가 100인 데이터가 전송되는 과정에서 유실되었다고 하면, 수신 시스템에서의 Rcv Buffer는 위와 같이 sequence number가 100인 segment를 제외한 나머지 segment만 있을 것이다.
이때 수신 시스템에서는 ACK 응답을 보내야하는데, 아래와 같이 보낸다.
- sequence number가 0인 데이터에 대해서는 ACK#100 (0~99까지는 잘받았으니 이제 받아야하는게 sequence number가 100인 data야~)
- sequence number가 200인데이터에 대해서도 ACK#100 이 전송된다. 왜냐하면 TCP 프로토콜은 순서를 보장해야한다. 따라서 Rev Buffer는 아직 100번째 segment가 오지 않았기때문에 ACK#100을 응답으로 전송한다.
- sequence number가 300 인 데이터에 대해서도 위와같은 이유로 ACK#100이 응답으로 전송된다.
위과정에서 결국 sequence number가 100인 데이터가 재전송이 되겠지만, timeout이 걸릴때까지 대기해야한다. 따라서 TCP는 3개의 중복 ACK를 수신할 때, 타이머에 관계없이 세그먼트를 재전송하는 fast retransmit을 사용한다. 이때 주의해야 하는점은 3개의 중복 ACK가 의미하는건 알맞은 응답에 대한 ACK 를 제외한 3개의 중복 ACK를 받아야 재전송한다는 의미이다.
위 사진처럼 실제론 4개의 응답을 받아야 fast retransmit에 의해 segment를 재전송 한다.
즉 Timeout 이 지나지 않더라도, fast retransmit(빠른 재전송) 을 사용하게되면 더 효율적으로 TCP 통신을 할수 있다.
'네트워크' 카테고리의 다른 글
RDT(Reliable Data Transfer) (1) | 2023.11.21 |
---|---|
Multiplexing, deMultiplexing (0) | 2023.10.25 |
소켓 (0) | 2023.10.23 |
DNS (0) | 2023.10.19 |
HTTP1/HTTP2/HTTP3 (0) | 2023.10.19 |
RDT(Reliable Data Transfer)
3.4 rdt 원리
TCP 프로토콜은 신뢰적인 데이터 전송 rdt(reliable data transfer) 를 지원한다.
rdt 를 보장하기 위해 필요한건 다음과 같으며 순서대로 설명해보겠다.
- error detection
- feedback
- sequence number
- timer
TCP 의 세그먼트는 사실 트랜스포트 계층 이외도 전송계층, 링크계층, 물리계층을 모두 타고 이동하여 상대방에게 전송된다.
즉 트랜스포트 계층 이외 계층을 통해 데이터가 전송될때도 TCP 의 rdt 가 지켜지기 위해 TCP는 여러 헤더를 사용한다.
데이터는 여러 라우터를 거쳐 상대의 종단 시스템에 도착할 것이다. 이때 발생할수 있는 문제(rdt 를 위배할수있는 문제)는 2가지 정도 된다.
- 데이터 이동중 에러 발생 (데이터는 결국 010101 이런식으로 보내질텐데, 데이터가 손상될수 있다.)
- 데이터 Loss (앞서배운 큐잉지연 등에 의해 데이터가 손실될수 있다.)
rdt를 위배할수 있는 위 2가지 사항을 극복하면 TCP 프로토콜은 rdt를 보장할수 있을 것이다.
1. error detection
우리가 수신시스템으로 보내는 데이터가 여러 라우터를 거치는 와중에 데이터에 에러가 발생할 가능성이 있다.
TCP 는 기본적으로 error detection 을 보장한다. 헤더에 checksum 필드를 추가하여 해당 데이터에 이상 유무를 수신단에서 확인할수 있게 한다.
2. feedback
수신 시스템에서 체크섬 필드를 통해 데이터의 이상유무를 확인했을때 해당 데이터에 이상이 있다면 송신 시스템으로 부터 데이터를 다시 전송받아야한다.
위와 같은 매커니즘을 사용하려면, 송신 시스템은 수신시스템으로부터 이상없는 데이터를 받았는지에 대한 feedback 이 필요할 것이다.
이때 사용하는 것이 ACK(positive acknowledgment) 와 NAK(negative acknowledgment) 이다.
ACK, 와 NAK 는 일종의 피드백이다. 수신자 축에서 받은 데이터에 대해 오류가 있으면 송신자 측으로 NAK 응답을 보내고, 오류가 없다면 ACK 응답을 송신자 측으로 보낸다.
❗️ACK 손상 가능성
위 설명대로 일종의 피드백 형태인 ACK 와 NAK 를 사용하면 데이터가 이동중 에러가 발생했을 상황을 극복할수 있을것 같다.
하지만 우린 ACK 또는 NAK 패킷이 손상가능하다라는 가능성을 고려해야한다.
즉 수신 시스템이 이상이 있는 데이터를 받아 송신 시스템에게 NAK 응답을 했는데, 만약 NAK 응답자체가 송신시스템으로 가는 도중에 손상이 발생한다면?
위와같은 상황을 해결하기 위해 tcp 프로토콜은 sequence number를 사용한다.
3. sequence number
수신자측은 데이터를 받을때 송신자 측에게 ACK 또는 NAK 응답을 반드시 보낸다.
위와같은 ACK응답이 손상되었을때 재전송 을 해결방안으로 생각한 사람이 있을수도 있다.
ACK응답이 오지 않으면 그외의 경우는 모두 재전송을 한다고 가정했을때, 문제가 발생할수 있는 경우는 아래와 같다.
수신자 측에서 오류가 없는 데이터 A 를 받았다고 가정한다.
그후 수신자는 송신자에게 데이터 A에 대한 ACK 응답을 할것이다.
하지만 이 ACK 응답이 가는도중 데이터에 에러가 발생하여 송신자 측에 응답이 도착했을땐 ACK 인지 NAK인지 판단할수 없다.
따라서 송신시스템은 데이터 A를 수신시스템에게 재전송 할 것이다.
데이터 A 가 수신시스템에게 왔다, 수신시스템은 데이터 A가 재전송이 된 데이터인지, 새로운 데이터인지 판단할수 없다.
위 가정에서 보면 결국 수신시스템은 수신한 데이터가 재전송을 위한 데이터인지, 새로운 데이터인지 판단해야한다.
이런 상황을 타개하기위해 sequence number 를 사용하는 것이다.
sequence number 는 송신자 측에서 보내는 세그먼트에 고유한 순차 번호를 부여하는 것이다.
수신자 측에서는 순차 번호를 통해, 받은 데이터가 중복된 데이터인지 새로운 데이터 인지 확인할수 있다.
수신자 측에서 오류가 없는 데이터 A (헤더에 순차번호가 0번인) 를 받았다고 가정한다.
그후 수신자는 송신자에게 데이터 A에 대한 ACK 응답을 할것이다.
하지만 이 ACK 응답이 가는도중 데이터에 에러가 발생하여 송신자 측에 응답이 도착했을땐 ACK 인지 NAK인지 판단할수 없다.
따라서 송신시스템은 데이터 A를 수신시스템에게 재전송 할 것이다.
데이터 A 가(헤더에 순차번호가 0번인) 수신시스템에게 왔다, 수신시스템은 순차번호를 통해 해당 데이터가 재전송된 데이터 인지 확인할수 있으며 해당 데이터를 버린다.
sequence number 를 도입하는 순간 NAK 의 필요성이 사라진다. 만약 수신자 측에서 ACK, 또는 NAK 응답을 보낼때 수신자가 지금까지 받은 데이터의 sequence number 를 같이 보내준다면 NAK 응답이 필요없어 진다. 이를 acknowledgement number 라고 한다.
acknowledgement number 는 수신자가 다음에 기대하는 바이트의 순서번호를 나타낸다.
즉 마지막으로 성공적으로 받은 데이터 바이트의 순서번호에 1을 더한다.
<정상적인 데이터를 받았을 경우>
수신자 측에서 오류가 없는 데이터 A (헤더에 순차번호가 0번인) 를 받았다고 가정한다.
그후 수신자는 송신자에게 데이터 A에 대한 ACK#1 (순차번호가 0번인 것까지는 완벽하게 받았으니) 응답을 할것이다.
송신자 측에선 ACK#1 을 통해 그다음 데이터인 1번 데이터를 전송해야 하는것을 알수있다.
<비정상 적인 데이터를 받았을 경우>
수신자 측에서 오류가 있는 데이터 B (헤더에 순차번호가 1번인) 를 받았다고 가정한다.
그후 수신자는 송신자에게 데이터 B에 대한 재전송을 위해 ACK#1 (순차번호가 0번인 것까지는 완벽하게 받았으니) 응답을 할것이다.
송신자 측에선 ACK#1 을 통해 순차번호가 1번인 데이터 B를 재전송 해야한다는 것을 인지할수 있다.
4. timer
지금까지 본 error detection, feed back, sequence number 3가지를 사용하면 rdt를 지키기위해 트랜스포트 계층 외 계층에서 발생할수 있는 error 에 대한 해결방안은 모두 제시했다.
이제는 Loss 에 대한 해결책만을 확인하면 된다.
Loss 는 잘못된 응답이 오고 안오고를 떠나서 응답자체가 안오는 경우에 대해서는 어떻게 해결을 할것이냐? 에 대한 물음이다.
즉 송신자 측에서 데이터를 보냈는데 데이터가 가는도중에 패킷이 유실되든, 수신자측에서 받은 데이터에 대한 응답이 송신자측으로 가는 도중에 유실이 되든 사실 송신자 입장에선 응답이 안오는 같은 상황이다.
단순히 생각해봐도 해당 응답이 올때까지 무한정 대기할수는 없다. 따라서 우린 timer 를 사용한다.
timer를 사용하여 일정 시간이 지나도록 응답이 오지 않으면 재전송을 하게한다.
대기하는 시간은 일반적으로 rtt(round-trip-time) + margin 으로 잡는다.
참고로 segment 를 보낼때마다 rtt를 측정하여, 재전송 타이머를 동적으로 조절한다 (매번 네트워크 지연시간이 다르기 때문에 첫번째 rtt 를 계속해서 타이머로 설정하는데에는 무리가 있다).
또한 이 평균을 측정하는데 있어서 재전송 에 대해서는 포함하지 않는다.
'네트워크' 카테고리의 다른 글
TCP(1) (1) | 2023.11.21 |
---|---|
Multiplexing, deMultiplexing (0) | 2023.10.25 |
소켓 (0) | 2023.10.23 |
DNS (0) | 2023.10.19 |
HTTP1/HTTP2/HTTP3 (0) | 2023.10.19 |
Multiplexing, deMultiplexing
3.1 트랜스포트 계층 서비스 및 개요

트랜스포트 계층은 애플리케이션 프로세스 간의 논리적 통신을 제공한다. 실제로는 각각의 프로세스들은 수많은 라우터와 다양한 형태의 링크들을 통해 연결되지만, 이러한 세부사항에 관계없이 각 종단간의 시스템간 메세지 전송을 위해 트랜스포트 계층에서 제공하는 논리적 통신을 사용한다.
각 계층별로 사용하는 데이터의 명칭은 아래와 같다.
- application : 메세지
- transport: 세그먼트 (RFC 에서 UDP 에 대한 패킷은 데이터 그램으로 표현한다)
- network: 데이터그램
- link: 프레임
- physical: 비트
네트워크 계층과 트랜스포트 계층 차이
트랜스포트 계층은 프로세스대 프로세스의 통신을 담당하며, 네트워크 계층은 호스트대 호스트 통신을 제어한다. 즉 각 계층은 고유의 역활을 수행하며 이전 계층의 데이터를 기반으로 작업을 한다.
예를들어 네트워크 계층은 트랜스포트 계층에서 받은 세그먼트를 데이터그램으로 캡슐화 하며, 이 데이터그램을 링크 계층으로 전달한다.
3.2 다중화 및 역 다중화
트랜스포트 계층에서 사용되는 프로토콜은 UDP, TCP 프로토콜이다. UDP 와 TCP 프로토콜이 공통적으로 제공하는 기능은 다중화(transport-layer-multiplexing) 및 역다중화 (demultiplexing) 와 오류 검출 이다.
multiplexing
각 종단 시스템에 존재하는 프로세스는 소켓을 갖는다. 수신 호스트의 트랜스포트 계층은 네트워크 계층으로 부터 데이터를 받는다. 이후 데이터를 프로세스로 전달을 해야하는데 앞서 말했듯이 프로세스로 전달을 하기위해선 각 프로세스에 맞는 소켓으로 전달을 해야한다.
이렇게 데이터를 올바른 프로세스나 서비스로 전달하기 위해 적절한 소켓을 사용하는 것 역다중화 라고 한다.
송신 시스템의 트랜스포트 계층은 애플리케이션 계층으로부터 받은 데이터에 헤더 정보를 추가하여 세그먼트로 만들고, 이를 네트워크 계층으로 전달하는 것을 다중화라고 한다

위 사진에서 프로세스 P1 과 P2 가 올바른 데이터를 받기 위해선 받기 위해선 반드시 역다중화가 필요하며, 이 과정은 앞서 말했듯이 트랜스포트 계층에 도착한 세그먼트를 각 프로세스의 소켓으로 전달되야 함을 의미한다.
UDP 세그먼트

위 사진은 대략적인 UDP세그먼트의 형태이다. 대부분의 프로토콜은 해당 프로토콜의 헤더에 핵심 기능이 담겨있다.
위 세그먼트의 형태를 보면 출발지 및 목적지 포트번호가 존재한다. 즉 역다중화에 사용할 목적지 포트번호를 세그먼트의 헤더에 기록하고 있으며, 이 포트번호를 통해 수신 종단시스템의 특정 프로세스 소켓에 역다중화가 정확하게 될수 있는것이다.

위에서 보이는것 처럼 UDP 소켓이 목적지 IP 주소와 목적지 포트 번호로 구성된 두 요소로 된 집합에 의해 식별 된다.
출발지 포트 번호를 헤더에 추가하는 이유는 서버 측에서 세그먼트를 다시 호스트 A로부터 받기 위해 서버 B에서 출발한 세그먼트의 목적지 주소로 사용하기 위함이다.
TCP 세그먼트
UDP 의 세그먼트는 출발지 포트와 목적지 포트번호를 가지고 있음을 확인했다.
TCP의 세그먼트는 UDP 와 다르게 4개의 요소(four-tuple)를 가지고있다.
- 출발지 IP 주소
- 출발지 포트 번호
- 목적지 IP주소
- 목적지 포트번호
TCP 세그먼트는 역다중화를 위해 위 4가지 요소를 사용하며 이를 통해 알맞은 프로세스의 소켓을 통해 데이터를 전달한다.

위 사진을 보면 호스트 A 와 호스트 C 는 웹서버 B 에 TCP 연결후 데이터를 전송하고 있다. UDP 는 비연결 프로토콜이지만 TCP 는 연결 프로토콜임을 기억해야한다. UDP 를 사용하면 서버측에선 하나의 소켓(고유한 포트번호)에서 여러 데이터를 동시에 받는 시스템이고, TCP 프로토콜을 사용하면 서버측에선 하나의 리스닝 소켓을 통해 연결을 수락하며, 각 연결을 4개의 요소를 통해 고유한 소켓을 사용하여 데이터를 받는다.
즉 정리하자면
UDP에서는 하나의 포트에 하나의 소켓만 바인딩되지만, 여러 클라이언트로부터의 데이터를 수신할 수 있다.
TCP에서는 하나의 포트에 "리스닝 소켓"이 바인딩되며, 이 소켓을 통해 여러 개의 연결을 수락하고 각 연결에 대해 별도의 소켓이 할당된다. (즉 TCP 에선 80번 포트를 갖는 여러개의 소켓이 존재할수 있다 이 각 소켓은 4개의 요소로 인해 구분(인덱싱) 된다.)
위 사진에서 호스트 C는 웹서버 B와 2개의 TCP 연결을 하고있다. 우리가 기존에 사용한 UDP 세그먼트의 헤더와 다르게 TCP 세그먼트의 헤더엔 출발지 IP 및 목적지 IP 가 추가적으로 있다.
결국 이 4개의 요소를 사용하여 목적지에 특정 소켓을 구분할수 있는것이다. 사진 왼쪽에 있는 헤더와 오른쪽에 있는 헤더는 출발지 포트가 다르기 때문에 웹서버 B에서 데이터를 보내야할 소켓을 구분할수 있을거고, 오른쪽 헤더와 아래 헤더는 출발지 IP 를 통해 서로다른 소켓을 구분하여 역다중화를 적절하게 수행할수 있을 것이다.
'네트워크' 카테고리의 다른 글
TCP(1) (1) | 2023.11.21 |
---|---|
RDT(Reliable Data Transfer) (1) | 2023.11.21 |
소켓 (0) | 2023.10.23 |
DNS (0) | 2023.10.19 |
HTTP1/HTTP2/HTTP3 (0) | 2023.10.19 |
소켓
소켓
소켓이란 각 프로세스간 전송(transport) 계층과 애플리케이션 계층을 연결하는 인터페이스이다.
즉 소켓에 읽기, 쓰기 를 통해 서로다른 네트워크 상의 두 컴퓨터는 통신한다. (서로다른 종단 시스템 간의 프로세스 통신)
전송 계층은 우리가 앞서 배웠던것처럼 TCP, UDP 두가지 방식이 있다. 즉 소켓을 사용하는 방법 또한 TCP, UDP 두가지 방식이 있다.
UDP 방식

UDP 통신을 할땐 위와 같은 과정을 거친다. UDP 는 비연결 통신 이므로 따로 연결을 설정하거나 종료하는 과정이 없다.
즉 클라이언트 측에서 메세지를 보낼때마다 어느 서버로 보내는지 명시를 해야하며, 서버측 또한 어느 클라이언트로 부터 데이터를 받는지 확인을 해야한다. 따라서 클라이언트 측의 메세지를 보내는 메서드의 이름이 sendto()
이다.

위와같이 UDP 프로토콜을 사용함에도, connect()
함수를 사용할수 있다. 하지만 이 connect()
메서드가 TCP 방식에서 사용할 connect()
함수와는 같지 않으며, 단순히 클라이언트 측의 소켓에 대상 주소를 지정 해주는 것으로 이해해야한다.
위처럼 사용하면 클라이언트 측에서 메세지를 보낼때 마다 IP 주소를 명시하지 않아도 된다(따라서 클라이언트에서 메세지를 보낼때 사용하는 메서드명이 sendto()
가 아닌 send()
이다.
TCP 방식

TCP를 사용하여 통신을 할땐 위와같은 과정을 거친다.
TCP 서버
- bind() : 소켓을 특정 IP 주소와 포트 번호에 바인딩한다. IP 주소는 대개 서버가 실행 중인 시스템의 주소이며. 포트번호는 HTTP를 통해 요청을 받는다면 80번 포트로 바인딩 할것이다.
- listen(): 이 함수는 소켓이 클라이언트로부터 들어오는 연결을 수락할 준비가 되었음을 운영체제에 알린다.
- accept(): 클라이언트의 연결 요청을 대기한다. 연결 요청이 들어오면,
accept()
는 새로운 소켓을 반환한다. 이 새로운 소켓을 사용하여 클라이언트와 통신한다. - recv() : 클라이언트 쪽에서 전송하는 데이터를 수신한다.
- send(): 요청에 대한 동작을 처리한후, 클라이언트 쪽에 데이터를 전송한다.
위 과정이 끝난다면 서버는 다시 accept()
함수를 실행한다. 즉 다른 클라이언트의 connect()
요청이 올때까지 기다린다.
📌TCP 클라이언트는 bind()
부분이 없다. 그이유는 서버측은 어떤 포트를 사용하는지 정해져야 하지만 클라이언트는 어떤 포트가 사용되는지가 중요하지 않다. (클라이언트는 OS 가 랜덤으로 포트를 지정한다.)

또한 listen()
때 사용하는 소켓과 accept()
때 사용하는 소켓이 다르다. listen()
에 사용되는 소켓은 환영 소켓(listening socket) 이며, accept()
에 사용되는 소켓은 연결 소켓(connection socket)이다.
즉 서버에 연결된 클라이언트가 100개라면, 환영 소켓 1개(3-way-hand-shake) + 각 클라리언트에 연결된 연결소켓 100개 총 101개의 소켓이 서버측에 존재하게 된다.
TCP 클라이언트
- connect() : 서버측에 연결을 시도한다.
- send(): 서버측에 데이터를 전송한다.
- recv() : 서버측으로 부터 온 데이터를 수신한다.
Python 으로 TCP 서버 및 클라이언트 구현
TCPClient.py

위 코드는 TCP 연결을할때 클라이언트 측의 코드이다.
serverPort= 12000
: 위 코드는 서버의 12000 포트로 연결을 한다.clientSocket = socket(AF_INET, SOCK_STREAM)
: 클라이언트측의 소켓을 생성한다. 이때 첫번째 파라미터는IPv4
를 사용함을 의미하며,SOCK_STREAM
은 UDP 소켓이 아닌 TCP 소켓임을 의미한다.clientSocket.connect((serverName, serverPort))
: TCP 연결을 할땐, 데이터를 보내기전 TCP 연결이 먼저 클아이언트와 서버 사이에 설정이 되어야 한다..connect()
메서드는 연결할 서버의 이름 및 포트를 파라미터로 받으며, 해당 코드가 실행된 후 3-way-handshake 가 수행되고 클라이언트 서버간 TCP연결이 설정된다.
UDP 는 연결이 없는 프로토콜이다. 따라서 메세지 (패킷) 을 보낼때마다 IP 와 포트를 지정해야 하지만, TCP 는 연결 지향적 프로토콜이다.
즉 최초 클라이언트와 서버 사이에 3-way-handshake 를 통해 연결을 설정하면, 해당 연결에 대한 소켓은 특정 IP 포트와 연결된다. 따라서 UDP 와 다르게 데이터를 전송할 때 마다 IP 와 포트를 다시 지정할 필요가 없다.
TCPServer.py

위 코드는 TCP 연결을 할때 서버측의 코드이다.
serverSocket = socket(AF_INET, SOCK_STREAM)
: 서버측 또한 TCP 연결을 위해SOCK_STREAM
을 사용하는 소켓을 만든다. 이때 생성되는serverSocket
은 환영 소켓 이다.connectionSocket , addr = serverSocket.accept()
:accept()
메서드를 통해 특정 클라이언트의 연결요청이 오면, 새로운 소켓 (연결소켓connectionSocket
) 을 반환한다. 그 뒤 클아이언트와 서버는 핸드 셰이킹을 완료한후 클라이언트의clientSocket
과 서버의connectionSocket
간의 TCP 연결을 생성한다.
'네트워크' 카테고리의 다른 글
RDT(Reliable Data Transfer) (1) | 2023.11.21 |
---|---|
Multiplexing, deMultiplexing (0) | 2023.10.25 |
DNS (0) | 2023.10.19 |
HTTP1/HTTP2/HTTP3 (0) | 2023.10.19 |
HTTP) TCP 및 3-way handshake (1) | 2023.05.09 |
DNS
2.4 DNS: 인터넷의 디렉터리 서비스
우리가 흔히 쓰는 www.naver.com
에서 www는 호스트 네임(hostname) 이름, naver는 도메인 네임 com 은 탑레벨 도메인 이다.
하지만 라우터는 www.naver.com
과 같은 문자보단 IP주소로 특정 호스트를 식별한다.
즉 우리가 호스트 네임을 통해 특정 서버로 요청을 보낼때 해당 이름에 해당하는 IP주소를 들고 있는 분산 데이터 베이스 이다.
DNS(domain name system) 는 애플리케이션 계층 프로토콜이며, 분산 및 계층 구조로 되어있다. 하나의 서버에 모든 데이터를 담고있다면 여러 문제가 발생할수 있고 트래픽이 한곳으로 집중될수 있기 때문에 DNS는 분산 데이터베이스 구조로 되어있다. 또한 DNS 는 UDP 프로토콜 상에서 수행되며, 포트번호 53을 사용한다.
❗️DNS 는 어떻게 보면 통신을 하기위한 준비과정이다(즉 최대한 빠르게 데이터를 얻어오는게 중요하다). 또한 DNS 를 통해 IP 주소를 가져올때 오가는 데이터의 양은 매우작으며, 이는 손실이되더라도 충분히 재요청을 할수있는 정도이다. 즉 TCP가 신뢰있는 통신을 보장한다지만, TCP 를 사용하는것 만으로도 3-way-handShake 등 배보다 배꼽이 더 큰 상황이 올수 있기 때문에, UDP 프로토콜을 사용한다.
2.4.2 DNS 구성 및 동작 과정

앞서 말했듯 DNS 는 분산 및 계층 구조로 되어있다. 위 그림처럼 루트 DNS 서버 , 최상위 레벨 도메인 네임 DNS 서버 (TLD, top-level domain), 책임 DNS 서버 로 구성되어있다.
루트 DNS 서버 : TLD 서버의 IP 주소들을 제공한다.
TLD 서버: com, org, net, edu 와 같은 상위 레벨 도메인과 kr, uk, fr 등과 같은 모든 국가의 상위 레벨 도메인에 대한 서버이다. 책임 DNS 서버에 대한 IP 주소를 제공한다.
책임(authoritative) DNS 서버: 호스트 이름을 IP 주소로 매핑하는 공개적인 DNS 레코드를 갖고 있다.
로컬 DNS 서버: 대학이나 주거지역 ISP들이 갖는 DNS 서버이다.
- 호스트가 ISP 에 연결될때 그 ISP는 로컬 DNS 서버로부터 IP주소를 호스트에게 제공한다.
- 로컬 DNS 서버는 캐싱 기능을 하며, 따라서 특정 호스트 네임에 대한 IP 주소를 저장하여, 추후 올수있는 같은 요청에 대해 더 빠르게 응답할수 있도록 한다. (IP 주소는 유동적이기 때문에 네임에 대한 IP 주소를 저장시 TTL(Time to live) 컬럼을 두어 특정 기간이 지나면 소멸되게 한다.)

위 사진을 통해 특정 호스트로 메세지를 보내고싶을때, 수신 호스트에대한 IP 주소를 DNS 서버를 통해 얻는 과정을 살펴보겠다.
- 로컬 DNS 서버 요청: 사용자의 기기는 먼저 로컬 DNS 서버에 웹사이트의 IP 주소를 요청한다.
- 로컬 DNS 서버에 해당 웹사이트의 IP 주소가 캐싱되어 있다면, 이 주소를 사용자의 기기에게 바로 반환한다. (이 예에서는 해당 정보가 로컬 DNS 서버에 없다고 가정한다).
- 루트 DNS 서버 요청: 로컬 DNS 서버는 루트 DNS 서버에 웹사이트의 IP 주소를 요청한다. 루트 DNS 서버는 웹사이트의 IP 주소를 알고 있지 않지만, 해당 도메인의 Top Level Domain (TLD, 예: .com, .org)을 관리하는 TLD 서버의 IP 주소를 로컬 DNS 서버에게 알려준다.
- TLD 서버 요청: 이후 로컬 DNS 서버는 TLD 서버에게 웹사이트의 IP 주소를 요청한다. TLD 서버는 해당 도메인을 관리하는 권한있는 (Authoritative) DNS 서버의 IP 주소를 로컬 DNS 서버에게 반환한다.
- 권한있는 DNS 서버 요청: 로컬 DNS 서버는 마지막으로 권한있는 DNS 서버에 웹사이트의 IP 주소를 요청한다. 권한있는 DNS 서버는 웹사이트의 실제 IP 주소를 로컬 DNS 서버에게 제공하고, 로컬 DNS 서버는 이 IP 주소를 사용자의 기기에게 반환한다.
❗️일반적으로 TLD 서버가 책임 DNS 서버에 대한 주소를 알지 못한다. 대신 TLD 서버는 호스트 이름에 대한 책임 DNS 서버를 아는 중간 DNS 서버를 알고 있으며, 이러한 중간 DNS 서버를 거쳐 최종적으로 책임 DNS 서버의 IP 주소를 얻게 된다.
2.4.3 DNS 레코드와 메시지
DNS 서버는 호스트 이름을 IP 주소로 매핑하기 위한 레코드를 저장한다.
레코드의 형태는 다음과 같다. (Name, value, Type, TTL)
TTL 은 위에서 말한 Time to Live 이며, 여기서 핵심은 Type
이다. 어떤 타입인지에 따라 name 과 value 에 저장하는 값들이 다르다.
Type 에는 4가지 종류 A Type, NS Type, CNAME Type, MX Type 이있다. 지금은 A, NS 타입에 대해서만 알아보겠다.
A타입
- Name : 호스트이름
- Value: 호스트 이름에 대한 IP 주소
NS타입
- Name: 도메인
- Value: 도메인 내부의 호스트에 대한 IP 주소를 얻을 수 있는 방법을 아는 책임 DNS 서버

이사진을 기반으로 각 서버가 어떤 형태로 레코드를 저장하고 있는지 알아보자. 이때 TLD DNS 의 도메인명은 dns.edu, IP 주소는 2.2.2.2 로가정한다. (편의상 TTL 은 쓰지않았다)
루트 DNS 서버
name | value | Type |
---|---|---|
.edu | dns.edu | NS |
dns.edu | 2.2.2.2 | A |
NS 와 A 타입 데이터는 항상 같이 다닌다. 즉 위 레코드는 .edu 를 처리할수 있는 서버의 도메인명은 dns.edu 라는 것을 알려주며, A 타입 레코드를 통해 dns.edu 서버의 IP 주소를 알려준다.
로컬 DNS 서버는 위와 같은 데이터를 통해 TLD DNS 서버(2.2.2.2) 에 요청을 하면 TLD 서버는 위와 같은 레코드를 통해 IP 주소를 응답으로 준다.
이때 책임 DNS 서버는 NS 타입 레코드를 저장하지 않는데, 그이유는 책임서버에 결국 요청 호스트가 원하는 IP 주소가 있기 때문이다. NS 레코드 라는것 자체가 우리가 원하는 도메인을 찾으려면 어떤 도메인으로 요청을 하면 될까? 에대한 레코드 이기때문에 최종적인 책임 DNS 서버에는 NS 레코드가 없는 것이다.
ChatGpt 한테 그렇다면 TLD 서버는 항상 책임서버에 대한 IP주소를 가지고 있냐 물어보니 다음과 같이 대답했다.
답변: 루트 DNS 서버는 일반적으로 TLD DNS 서버에 대한 A 레코드를 저장하지 않습니다.
대신 NS 레코드로 해당 TLD를 처리할 수 있는 TLD 서버의 이름을 알려줍니다.
로컬 DNS 서버가 초기 DNS 쿼리를 시작할 때, 기본적으로 루트 서버의 IP 주소는 이미 알고 있습니다.
루트 서버에서는 요청받은 도메인 이름에 대한 적절한 TLD 서버의 NS 레코드를 반환합니다.
그럼 로컬 DNS는 어떻게 해당 TLD 서버의 IP 주소를 알게 될까요?
로컬 DNS 서버는 일반적으로 "root hints"라고 하는 파일을 가지고 있습니다.
이 파일은 모든 루트 DNS 서버와 주요 TLD 서버의 IP 주소를 포함하고 있습니다.
이 정보를 사용하여 로컬 DNS 서버는 TLD 서버에 직접 쿼리를 보낼 수 있습니다.
즉, 루트 DNS 서버는 TLD 서버의 IP 주소를 직접 제공하지 않습니다.
대신, 로컬 DNS 서버가 루트 힌트나 이전에 캐싱된 정보를 사용하여 해당 TLD 서버의 IP 주소를 알아낼 수 있게 됩니다.
현실에선 우리가 이론적으로 배운 내용과 100% 같게 돌아가진 않는것 같다.
결론적으로 만약 우리가 어떤 네트워크를 만들고, 책임서버를 만들었다면 우리가 해야할일은 TLD 서버에 우리의 책임서버 네임과 IP 를 등록하여 다른사람들로 하여금 접속할수 있게 만들면 된다.!
'네트워크' 카테고리의 다른 글
RDT(Reliable Data Transfer) (1) | 2023.11.21 |
---|---|
Multiplexing, deMultiplexing (0) | 2023.10.25 |
소켓 (0) | 2023.10.23 |
HTTP1/HTTP2/HTTP3 (0) | 2023.10.19 |
HTTP) TCP 및 3-way handshake (1) | 2023.05.09 |
HTTP1/HTTP2/HTTP3
HTTP/1 & HTTP/2 & HTTP/3
HTTP/1
HTTP/1: HTTP/1을 사용하면 클라이언트가 서버에 같은 요청을 할때마다 개별적인 TCP connection이 필요했다. 즉 실제 요청을 하기전 3-way-hand-shake 하는 과정이 필요하다.
RTT(round-trip-time): 클라이언트가 HTML 파일을 서버측에 요청하고 HTML 파일이 클라이언트한테 도달할때 까지의 시간 이다.
위 사진은 HTTP/1 을 사용할때 발생하는 요청의 흐름이다. 데이터 요청을 하기위해 3-way-handshake 과정을 거치며 1 RTT 가 소요되고, 그후 실제 요청을 하고 받는데 1 RTT 총 2 RTT 가 필요하다.
이런 연결을 비지속 연결(non-persistent-connection) 이라 한다. HTTP/1 의 이런 한계를 극복하기 위해 나온것이 지속 연결(persistent connection) 을 사용하는 HTTP/1.1 이다.
HTTP/1.1
HTTP/1.1: keep-alive
라는 매커니즘을 통해 서버에 요청을 할떄마다 TCP connection이 필요한게 아닌 connection을 재사용할수있도록 했다. 이렇게 함으로서 request latency를 줄일수 있었는데 이 이유는 TCP연결을 시작할때 해야하는 3-WAY-Handshake 과정을 매번 하지 않아도 되기 때문이다. 즉 최초 요청을 하고나선 1 RTT 의 request latency 로 응답을 받을수 있다.
HTTP/1.1에서 새롭게 추가된 pipelining 기능을통해 Client는 서버로부터 응답이 오기전 여러개의 요청을 할수있게 되었다.
하지만 pipelining기능을 사용했을때, 서버가 하나의 response를 보내는데 많은 시간이 소요되면 그이후에 보내는 응답들또한 지연이되는 현상이 발생했다. 이때 먼저 전송이되야하는 response가 blocked되면 (ex) packet loss) 같은 connection에 존재하는 다른 요청들에게도 영향이 가는 현상이 발생했다. 이러한 현상을 HOLB (Head-of-line Blocking) 라고 한다. (TCP는 패킷을 순서대로 처리해야하기때문에 HOLB가 발생한다.)
HOLB때문에 여러웹브라우저들이 pipelining사용을 막았으며, 여러 통신을 하기위해선 병렬적으로 여러개의 connection을 사용해 데이터를 가져와야했다.
HTTP/2
HTTP/2: HTTP/2부터는 하나의 TCP connection을 통해 여러개의 request를 stream의 형태로 보낼수 있게되었다.
이로인해 HTTP/1.1 pipelining을 사용하지 못해 여러개의 connection을 사용하여 병렬적으로 데이터를 가져와야하는 문제를 해결했다.(각각의 stream은 서로 독립적이기 때문에 하나가 block되더라도 다른 하나에 영향을 주지 않는다) 즉 HOLB가 Application layer에서는 해결이 되었지만 TCP를 사용하는 transport layer에서는 HOLB문제를 해결하지는 못했다.
결론적으로 HTTP/2 는 요청과 응답을 프레임단위로 나워 인터리빙하고, 반대편 시스템 (클라이언트, 혹은 서버)에서 재조립한다.
HTTP/3
HTTP/3: 새로운 protocol QUIC이 등장한다. QUIC은 UDP를 base로 만들어졌으며 TCP가 가지고있던 HOLB와 같은 문제점을 해결하며 레이턴시의 한계를 뛰어넘고자 구글이 개발한 UDP기반의 protocol이다.
QUIC는 위에서 말했듯 UDP를 기반으로 만들어졌다. 따라서 TCP보다 속도가 빠르며, handShake과정또한 필요로 하지않는다(따라서 레이턴시가 감소한다). 하지만 UDP가 TCP에비해 신뢰도가 떨어진다는 사실을 알것이다. 그럼 QUIC는 신뢰도를 떨어뜨리는 대신 빠른 UDP를 사용하냐? 이건 아니다. 왜냐하면 UDP의 장점중 하나가 바로 커스터마이징이다.
커스터마이징, 말그래도 UDP를 커스터마징을 통해 신뢰도를 TCP와 비슷한 수준으로 높일수 있다.
그외에도 패킷 손실 감지에 걸리는 시간을 단축시키며, 멀티플렉싱을 지원... 등 여러 장점들이 있다. 자세한건 HTTP/3는 왜 UDP를 선택한 것일까? 이 블로그를 참조하자.
Reference
'네트워크' 카테고리의 다른 글
RDT(Reliable Data Transfer) (1) | 2023.11.21 |
---|---|
Multiplexing, deMultiplexing (0) | 2023.10.25 |
소켓 (0) | 2023.10.23 |
DNS (0) | 2023.10.19 |
HTTP) TCP 및 3-way handshake (1) | 2023.05.09 |