파이톨치

[socket programming] TCP/UDP 본문

대학수업/socket programming

[socket programming] TCP/UDP

파이톨치 2024. 4. 20. 21:31
728x90

TCP vs UDP: Internet transport-layer protocols

전송 계층 (3계층)의 두 가지 주요 프로토콜인 TCP(Transmission Control Protocol)와 UDP(User Datagram Protocol)의 특징을 설명하고 있습니다.

1. TCP와 UDP 모두 포트 번호를 사용합니다.
- 포트 번호는 응용 프로그램별 통신 엔드포인트로 사용되는 개념입니다.
16비트 부호 없는 정수로 0부터 65535까지의 범위를 가집니다.
엔드-투-엔드 전송을 제공합니다.


TCP(Transmission Control Protocol)

TCP(Transmission Control Protocol)는 인터넷에서 신뢰성 있는 데이터 전송을 위해 널리 사용되는 프로토콜입니다. 주요 특징은 다음과 같습니다:
1. 신뢰성: TCP는 데이터의 순서를 보장하고, 모든 데이터가 수신되었는지 확인하며, 중복된 데이터를 제거합니다. 이는 마치 파일 입출력과 유사한 안정적인 데이터 전송을 가능케 합니다. 경계 없음
2. 연결 지향성: TCP는 데이터 전송 전에 송신자와 수신자 간에 연결을 설정합니다. 이 연결은 3-way handshaking이라는 과정을 통해 이루어집니다. 연결이 수립되면 데이터 전송이 반복적으로 이루어지며, 전송이 끝나면 4-way handshaking을 통해 연결이 종료됩니다.
3. 흐름 제어: TCP는 수신자의 버퍼 오버플로우를 방지하기 위해 송신자의 전송 속도를 조절하는 흐름 제어 기능을 제공합니다.
4. 혼잡 제어: TCP는 네트워크 경로 상의 라우터 버퍼 오버플로우를 방지하기 위해 송신자의 전송 속도를 조절하는 혼잡 제어 기능을 제공합니다. 대표적인 방법으로는 TCP 슬로우 스타트가 있습니다.
5. 바이트 스트림 방식: TCP는 전송할 데이터를 바이트 단위로 나누어 전송하고, 수신 측에서 이를 재조립합니다. 이를 통해 대용량 데이터를 안정적으로 전송할 수 있습니다.
6. 양방향 통신: TCP는 한 번 연결이 수립되면 양방향 통신이 가능합니다. + 1 대 1 통신 

TCP는 신뢰성과 순서 보장, 그리고 지속적인 연결이 필요한 서비스에 적합합니다. 하지만 이러한 기능들로 인해 연결 설정, 혼잡 제어, 흐름 제어 등의 오버헤드가 발생하므로, 실시간성이 중요한 서비스에는 적합하지 않을 수 있습니다.
신뢰할 수 있고 순서대로 전달(TCP) • 혼잡 제어 • 플로우 제어 • 연결 설정, 1대 1 통신, 신뢰성 있는 순서 보장 바이트 스트림, 전이중 통신 

 

TCP 세그먼트 헤더, 40바이트 

- 소스/목적지 포트 번호
- 순서 번호: 세그먼트 데이터의 첫 바이트 "번호"
- 확인 응답 번호: 다른 쪽에서 기대되는 다음 바이트 번호(누적 ACK)
- 윈도우 크기: 수신자가 받을 준비가 된 바이트 수  
- 체크섬 등 플래그 비트

TCP(Transmission Control Protocol)는 신뢰성 있는 데이터 전송을 위해 연결 설정과 해제 시 특별한 과정을 거칩니다. 

 

연결 설정 시에는 '3-way 핸드셰이크'라는 방식을 사용합니다:
1. 클라이언트가 서버에게 SYN(synchronize) 플래그를 1로 설정하고, 초기 시퀀스 번호(seq)를 x로 하여 전송합니다.
2. 서버는 클라이언트에게 SYN 플래그를 1로, ACK(acknowledgement) 번호를 x+1로, 그리고 자신의 초기 시퀀스 번호(seq)를 y로 하여 전송합니다. 
3. 클라이언트는 서버에게 ACK 번호를 y+1로 하여 전송합니다. 이 단계에서부터 클라이언트는 데이터 전송을 시작할 수 있습니다.


연결 해제 시에는 '4-way 핸드셰이크'를 사용합니다:
1. 클라이언트가 서버에게 FIN(finish) 플래그를 1로, 시퀀스 번호를 x로 하여 전송합니다. 이는 클라이언트가 더 이상 데이터를 보내지 않을 것임을 의미합니다.
2. 서버는 이를 확인(ACK)하고, 아직 보내지 못한 데이터가 있다면 계속 전송합니다.
3. 데이터 전송이 끝나면, 서버는 클라이언트에게 FIN 플래그를 1로, 시퀀스 번호를 y로 하여 전송합니다.
4. 클라이언트는 확인(ACK)을 보내고일정 시간(TIMED_WAIT) 동안 연결을 유지합니다. 이는 지연되어 도착하는 패킷을 처리하기 위함입니다.


이렇게 TCP는 연결 설정, 시퀀스 번호와 ACK를 통한 신뢰성 확보, 그리고 윈도우 기반의 플로우 제어와 혼잡 제어 등의 메커니즘을 통해 안정적인 데이터 전송을 보장합니다.


multiplexing at sender 

네트워크 통신에서 여러 애플리케이션이 동시에 데이터를 주고받을 때, 데이터가 어떤 애플리케이션에서 온 것인지 구분하는 것이 중요합니다. 이를 위해 '소켓'이라는 개념을 사용하는데, 소켓은 애플리케이션과 네트워크 사이의 접점 역할을 합니다.
데이터를 보낼 때는 각 애플리케이션의 소켓에서 데이터를 처리하고, 목적지 정보 등을 담은 헤더를 추가합니다. 이 헤더 정보는 나중에 데이터를 받는 쪽에서 어떤 소켓으로 전달해야 할지 판단하는 데 사용됩니다. 이 과정을 'demultiplexing'이라고 합니다. 즉, Transport layer 에서 세그먼트가 Application layer 로 전달 될 때, 올바른 소켓으로 전달 하는 과정 

Demultiplexing에는 두 가지 방식이 있습니다:
1. Connectionless demux (비연결형)
   - 서버로 들어오는 패킷의 목적지 포트 번호(dest port #)가 같으면 동일한 소켓으로 전달합니다. (UDP 방식인듯)
   - 예를 들어, 두 개의 패킷이 각각 source port 6428, 임의의 source port를 사용하지만, dest port는 모두 9157로 같다면 동일한 소켓으로 전달됩니다.
2. Connection-oriented demux (연결형)
   - 서버로 들어오는 패킷의 출발지 IP(source IP), 출발지 포트 번호(source port#), 목적지 포트 번호(dest port #)가 모두 같으면 동일한 소켓으로 전달합니다.
   - 예를 들어, IP 주소가 A인 호스트에서 IP 주소가 B인 호스트의 80번 포트로 데이터를 보내고, B에서 A의 9157번 포트로 응답을 보내는 경우, 이 둘은 같은 소켓으로 인식됩니다.

이렇게 demultiplexing을 통해 받은 쪽에서는 헤더 정보를 확인하여 데이터를 알맞은 소켓으로 전달할 수 있게 되고, 최종적으로 해당 애플리케이션이 데이터를 받을 수 있게 됩니다.


Pipelined protocols (파이프라인 프로토콜)


파이프라이닝은 TCP에서 데이터 전송 효율을 높이기 위해 사용되는 기술입니다. 송신자는 이전에 보낸 패킷에 대한 확인 응답(ACK)을 기다리지 않고, 여러 패킷을 연속적으로 전송할 수 있습니다. 이를 위해서는 패킷의 순서를 식별할 수 있는 번호 범위를 늘려야 하고, 송신자와 수신자 모두 패킷을 버퍼링할 수 있어야 합니다.


파이프라이닝에는 두 가지 일반적인 프로토콜 형식이 있습니다:
1. Go-Back-N (GBN):
   - 송신자는 최대 N개의 패킷을 확인 응답 없이 전송할 수 있습니다.
   - 수신자는 순서대로 패킷을 받으면 확인 응답을 보내지만, 중간에 패킷이 누락되면 확인 응답을 보내지 않습니다.
   - 송신자는 가장 오래된 미확인 패킷에 대한 타이머를 설정하고, 타이머가 만료되면 그 패킷부터 모든 미확인 패킷을 재전송합니다.

2. 선택적 반복 (Selective Repeat, SR):
   - 송신자는 최대 N개의 패킷을 확인 응답 없이 전송할 수 있습니다.
   - 수신자는 각 패킷에 대해 개별적으로 확인 응답을 보냅니다.
   - 송신자는 각 미확인 패킷에 대해 개별 타이머를 설정하고, 타이머가 만료되면 해당 패킷만 재전송합니다.

Go-Back-N은 구현이 상대적으로 간단하지만, 한 패킷이 손실되면 그 이후의 패킷도 모두 재전송해야 하므로 비효율적일 수 있습니다. 반면에 선택적 반복은 손실된 패킷만 재전송하므로 더 효율적이지만, 구현이 복잡합니다.

이러한 파이프라이닝 기술을 통해 TCP는 데이터 전송의 효율성을 높일 수 있습니다. 하지만 파이프라이닝을 사용하기 위해서는 송수신자 모두 충분한 버퍼 공간을 가지고 있어야 하며, 패킷 손실이나 지연에 적절히 대응할 수 있는 메커니즘이 필요합니다.

TCP 플로우 제어
- 수신자는 수신자-송신자 세그먼트의 TCP 헤더에 rwnd 값을 포함하여 사용 가능한 버퍼 공간을 "광고"
- RcvBuffer 크기는 소켓 옵션으로 설정 (일반적인 기본값은 4096바이트)
- 많은 OS에서 RcvBuffer를 자동 조정
- 송신자는 수신자의 rwnd 값까지만 확인응답되지 않은 ("전송 중") 데이터 양을 제한하여 수신 버퍼 오버플로우 방지 보장


UDP(User Datagram Protocol)

UDP(User Datagram Protocol)는 TCP와 달리 신뢰성보다는 속도와 간단함에 초점을 맞춘 프로토콜입니다. 주요 특징은 다음과 같습니다:
1. 비연결형: UDP는 데이터 전송 전에 연결을 설정하지 않습니다. 각 패킷은 독립적으로 처리되며, 매 패킷마다 목적지 정보를 포함해야 합니다.
2. 비신뢰성: UDP는 데이터 전송 후 수신 여부를 확인하지 않습니다. 따라서 패킷이 손실, 중복, 또는 순서가 바뀌어 도착할 수 있습니다. 즉, "최선의 노력" 서비스를 제공하지만, 데이터 전달을 보장하지는 않습니다. 
3. 데이터그램 방식: UDP는 데이터를 그대로 전송하는 데이터그램 방식을 사용 (경계 있음, 안 쪼갬)합니다. 송신 측은 데이터를 한 번에 전송하고, 수신 측은 그대로 받습니다.
4. 흐름 제어 없음: UDP는 수신 측의 버퍼 오버플로우를 방지하기 위한 흐름 제어 기능이 없습니다.
5. 혼잡 제어 없음: UDP는 네트워크 경로 상의 라우터 버퍼 오버플로우를 방지하기 위한 혼잡 제어 기능이 없습니다.

이러한 특성으로 인해 UDP는 신뢰성은 떨어지지만, 간단하고 빠른 데이터 전송이 가능합니다. 따라서 UDP는 다음과 같은 상황에 적합합니다:
- 실시간 화상 통신: 일부 패킷이 손실되더라도 큰 문제가 되지 않는 경우
- DNS(Domain Name System): 하나의 패킷 안에서 전체 요청과 응답이 처리되는 경우
- 단방향 통신: 수신 측의 응답을 기대하지 않는 경우 (예: 로깅, 모니터링)

 

왜 UDP가 있는가?
연결 설정 지연 없음, 혼잡제어  없음, 연결 상태 없음, 작은 헤더 크기 


소켓의 기본 함수:

네트워크 프로그래밍에서 소켓을 사용하여 통신을 하기 위해서는 여러 가지 함수들이 사용됩니다. 각 함수의 역할은 다음과 같습니다:

1. socket(int domain, int type, int protocol):
   - 이 함수는 매개변수로 지정한 도메인(domain), 유형(type), 프로토콜(protocol)에 따라 새로운 소켓을 생성합니다.
   - 도메인은 통신 영역(예: IPv4, IPv6)을, 유형은 소켓의 종류(예: TCP, UDP)를, 프로토콜은 사용할 프로토콜을 지정합니다.
2. bind(int s, const struct sockaddr *name, socklen_t *namelen):
   - socket() 함수로 생성된 소켓에 주소를 부여하는 역할을 합니다.
   - 이 함수를 통해 소켓과 특정 IP 주소 및 포트 번호를 연결할 수 있습니다.
3. listen(int s, int backlog):
   - 첫 번째 매개변수로 지정된 소켓을 수동 대기(passive waiting) 상태로 만듭니다.
   - 이 함수를 호출하면 해당 소켓으로 클라이언트의 연결 요청을 받을 수 있게 됩니다.
   - backlog 매개변수는 대기열의 최대 길이를 지정합니다. 'backlog'이 5로 설정되었을 때: 5개의 클라이언트가 연결을 요청하고 서버가 즉시 accept()를 호출하지 않으면, 이 5개의 요청은 대기열에 보관
4. accept(int s, struct sockaddr *addr, socklen_t *addrlen):
   - 서버 프로세스에서 사용되며, 클라이언트의 연결 요청을 수락하는 역할을 합니다.
   - 이 함수는 클라이언트와의 연결이 성립될 때까지 블로킹(blocking)됩니다.
   - 연결이 수립되면 새로운 소켓 파일 디스크립터를 반환하고, 이를 통해 클라이언트와 통신할 수 있습니다.
5. connect(int s, const struct sockaddr *name, socklen_t namelen):
   - 클라이언트 프로세스에서 사용되며, name이 가리키는 서버와의 연결을 시도합니다.
   - 이 함수는 서버와의 연결이 성립될 때까지 블로킹됩니다.
6. send(int s, const void *msg, size_t len, int flags):
   - 연결 지향형 소켓(예: TCP)에서 데이터를 전송하는 역할을 합니다.
   - s는 소켓 파일 디스크립터, msg는 전송할 데이터의 버퍼, len은 전송할 데이터의 길이, flags는 전송 옵션을 나타냅니다.
7. recv(int s, void *buf, size_t len, int flags):
   - 연결 지향형 소켓에서 데이터를 수신하는 역할을 합니다.
   - s는 소켓 파일 디스크립터, buf는 수신한 데이터를 저장할 버퍼, len은 버퍼의 크기, flags는 수신 옵션을 나타냅니다.

이러한 함수들을 사용하여 소켓을 생성, 주소 할당, 연결 수락, 데이터 전송 및 수신 등의 작업을 수행할 수 있습니다. 이를 통해 네트워크 상에서 프로세스 간 통신을 구현할 수 있습니다.

TCP/UDP Socket Programming

TCP Socket program에서 사용하는 함수들과 비교 할read/write 함수만 다름

 

 

 

728x90