HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
📚
CS 스터디
/
📚
TCP, UDP
📚

TCP, UDP

web, network 등 전송이 필요한 모든 곳에서 쓰이는 TCP, UDP에 대해 알아보자.
 

📤 Transport Layer

  • 한 마디로 정의하면?
    • End Point 간 신뢰성있는 데이터 전송을 담당하는 계층.
    • 신뢰성 : 데이터를 순차적, 안정적으로 전달.
    • 전송 : 포트 번호에 해당하는 프로세스에 데이터 전달.
      • TCP와 UDP는 ‘포트 번호’라는 숫자를 이용하여 컴퓨터 안의 어떤 서비스(애플리케이션)에게 데이터를 전달하면 좋은지를 식별함.
  • TCP와 UDP는 OSI 표준모델과 TCP/IP 모델의 전송계층에서 사용되는 프로토콜.
    • notion image
  • 잠깐 전송 계층에 대해 설명하자면
    • 전송계층은 송신자와 수신자를 연결하는 통신 서비스를 제공하고 IP에 의해 전달되는 패킷의 오류를 검사하며 재전송 요구 제어등을 담당하는 계층.
    • 쉽게 말해 데이터의 전달을 담당.
    • TCP와 UDP는 포트 번호를 이용하여 주소를 지정하는것과 데이터 오류검사를 체크하는 두가지 공통점을 가지고 있음.
    • 정확성(TCP)을 추구할지 신속성(UDP)을 추구할지를 구분하여 나뉨.
  • 전송 계층이 왜 필요한지 아직 모르겠다면
    • 데이터의 순차 전송이 원활하지 않음. ex) 송신자 1-2-3, 수신자 2-3-1
    • 송수신자 간의 데이터 처리 속도가 차이가 나기 때문에 발신자는 무한으로 전송할 수 있는 반면 수신자는 뇌처럼 처리할 수 있는 데이터량의 한계가 있어 초과할 위험이 있음.
    • 송수신자는 문제가 없지만 중간에 네트워크가 데이터를 늦게 처리한다면(네트워크가 혼잡하다면) 전송에 문제가 될 수 있음.
    • 결국 전송 계층이 없다면 데이터의 손실이 발생함.
 

🛡️ TCP

notion image
notion image
  • 데이터를 중요하게 생각하여 확실히 주고받고 싶을 때는 TCP(Transmission Control Protocol)를 사용함.
  • TCP는 통신할 컴퓨터끼리 보냈습니다, 도착했습니다라고 서로 확인 메시지를 보내면서 데이터를 주고받음으로써 통신의 신뢰성을 높임.
    • 이는 TCP의 가장 중요한 특징으로, 연결의 설정(3-way handshaking)과 해제(4-way handshaking)이 사용됨.
  • TCP는 연결 지향적 프로토콜임.
    • 클라이언트와 서버가 연결된 상태에서 데이터를 주고받는 프로토콜을 의미.
    • 클라이언트가 연결 요청(SYN 데이터 전송)을 하고, 서버가 연결을 수락하면 통신 선로가 고정되고, 모든 데이터는 고정된 통신 선로를 통해서 순차적으로 전달.
    • 그렇기 때문에 TCP는 데이터를 정확하고 안정적으로 전달.
  • TCP는 호스트간 신뢰성 있는 데이터 전달과 흐름을 제어함.
    • TCP는 패킷을 성공적으로 전송하면(ACK) 라는 신호를 날리고 만약에 ACK 신호가 제 시간에 도착하지 않으면 Timeout이 발생하여 패킷 손실이 발생한 패킷을 다시 전송.
    • 데이터를 송신할때마다 확인 응답을 주고받는 절차가 있으므로 통신의 신뢰성이 올라감.
💡
앞서 언급한 전송 계층이 없다면 발생할 문제 데이터의 순차 전송 보장, 흐름 제어, 혼잡 제어를 해결할 수 있음.
  • 웹이나 메일, 파일 공유 등과 같이 데이터를 누락시키고 싶지 않은 서비스가 사용 중.

TCP 헤더

송수신자의 포트 번호와 제어 비트(Flag Bit)에 SYN, ACK, FIN 등의 제어 번호가 있음.
송수신자의 포트 번호와 제어 비트(Flag Bit)에 SYN, ACK, FIN 등의 제어 번호가 있음.
  • SYN : 연결 설정 요구. TCP 에서 세션을 성립할 때 가장먼저 보내는 패킷, 시퀀스 번호를 임의적으로 설정하여 세션을 연결하는 데에 사용되며 초기에 시퀀스 번호를 보냄.
  • ACK : 응답 번호 필드가 유효한지 설정할때 사용하며 상대방으로부터 패킷을 받았다는 걸 알려주는 패킷. 클라이언트가 보낸 최초의 SYN 패킷 이후에 전송되는 모든 패킷은 이 플래그가 설정되어야 함.

3 way handshake

  • TCP 통신을 위한 네트워크 연결은 3 way handshake 이라는 방식으로 연결.
  • 3 way handshake 방식은 서로의 통신을 위한 관문(port)을 확인하고 연결하기 위하여 3번의 요청/응답 후에 연결이 되는 것을 말함.
  • 이 과정에서 가장 많은 시간이 소요되어 UDP방식보다 속도가 느려지는 주요 원인으로 지목.
notion image
  1. Client에서 Server에 연결 요청을 하기위해 SYN 데이터를 보낸다.
  1. Server에서 해당 포트는 LISTEN 상태에서 SYN 데이터를 받고 SYN_RCV로 상태가 변경된다.
  1. 요청을 정상적으로 받았다는 대답(ACK)와 Client도 포트를 열어달라는 SYN 을 같이 보낸다.
  1. Client에서는 SYN+ACK 를 받고 ESTABLISHED로 상태를 변경하고 서버에 ACK 를 전송한다.
  1. ACK를 받은 서버는 상태가 ESTABLSHED로 변경된다.
→ 위와 같이 3번의 통신이 정상적으로 이루어지면, 서로의 포트가 ESTABLISHED 되면서 연결됨.
💡
TCP state - LISTEN : 접속 요청을 기다리는 상태. - SYN_RECEIVED : 서버가 원격 클라이언트로부터 접속 요구를 받아 클라이언트에게 응답을 하였지만 아직 클라이언트에게 확인 메시지는 받지 않은 상태. - ESTABLISHED : 3 way-handshaking 이 완료된 후 서로 연결된 상태. - CLOSED : 완전히 종료

TCP 데이터 전송 방식

notion image
  1. Client가 패킷 송신.
  1. Server에서 ACK 송신.
  1. ACK를 수신하지 못하면 재전송.

4 way handshake

2번 ACK 송신 후 3번이 이루어지기 전에 일정 시간을 대기하며 Packet을 모두 보내는 과정이 있음.
2번 ACK 송신 후 3번이 이루어지기 전에 일정 시간을 대기하며 Packet을 모두 보내는 과정이 있음.
  1. 데이터를 전부 송신한 Client가 FIN 송신.
  1. Server에서 ACK 송신.
  1. Server에서 남은 패킷 송신.
  1. Server가 FIN 송신.
  1. Clinet가 ACK 송신.

예시

const net = require('net'); (() => { // When null, we are waiting for the first player to connect, after which we will // create a new game. After the second player connects, the game can be fully set // up and played, and this variable immediately set back to null so the future // connections make new games. let game = null; net.createServer((socket) => { console.log('Connection from', socket.remoteAddress, 'port', socket.remotePort); if (game === null) { game = new Game(); game.playerX = new Player(game, socket, 'X'); } else { game.playerO = new Player(game, socket, 'O'); game = null; } }).listen(58901, () => { console.log('Tic Tac Toe Server is Running'); }); })(); class Game { // A board has nine squares. Each square is either unowned or it is owned by a // player. So we use a simple array of player references. If null, the corresponding // square is unowned, otherwise the array cell stores a reference to the player that // owns it. constructor() { this.board = Array(9).fill(null); } hasWinner() { const b = this.board; const wins = [[0,1,2],[3,4,5],[6,7,8],[0,3,6],[1,4,7],[2,5,8],[0,4,8],[2,4,6]]; return wins.some(([x, y, z]) => b[x] != null && b[x] === b[y] && b[y] === b[z]); } boardFilledUp() { return this.board.every(square => square !== null); } move(location, player) { if (player !== this.currentPlayer) { throw new Error('Not your turn'); } else if (!player.opponent) { throw new Error('You don’t have an opponent yet'); } else if (this.board[location] !== null) { throw new Error('Cell already occupied'); } this.board[location] = this.currentPlayer; this.currentPlayer = this.currentPlayer.opponent; } } class Player { constructor(game, socket, mark) { Object.assign(this, { game, socket, mark }); this.send(`WELCOME ${mark}`); if (mark === 'X') { game.currentPlayer = this; this.send('MESSAGE Waiting for opponent to connect'); } else { this.opponent = game.playerX; this.opponent.opponent = this; this.opponent.send('MESSAGE Your move'); } socket.on('data', (buffer) => { const command = buffer.toString('utf-8').trim(); if (command === 'QUIT') { socket.destroy(); } else if (/^MOVE \d+$/.test(command)) { const location = Number(command.substring(5)); try { game.move(location, this); this.send('VALID_MOVE'); this.opponent.send(`OPPONENT_MOVED ${location}`); if (this.game.hasWinner()) { this.send('VICTORY'); this.opponent.send('DEFEAT'); } else if (this.game.boardFilledUp()) { [this, this.opponent].forEach(p => p.send('TIE')); } } catch (e) { this.send(`MESSAGE ${e.message}`); } } }); socket.on('close', () => { try { this.opponent.send('OTHER_PLAYER_LEFT'); } catch (e) {} }); } send(message) { this.socket.write(`${message}\n`); } }
 

🤔 TCP의 단점

원본 사진
원본 사진
원본 사진을 그림판에서 작업한 사진
원본 사진을 그림판에서 작업한 사진
  • 데이터로 보내기 전에 반드시 연결이 형성되어야 함(3 way-handshake로 시간 손실 발생).
  • 1 : 1 통신만 가능함.
  • 패킷을 조심만 손실해도 재전송.
  • 별로 티가 안나는 손실임에도 불구하고 재전송을 함. 서비스에 따라 불합리한 방식일 수 있음.
 

🏃 UDP

notion image
확인 작업 없이 Packet을 무조건 보냄.
확인 작업 없이 Packet을 무조건 보냄.
  • 그에 반해 데이터의 신뢰성은 제쳐두고 어쨌든 빨리 보내고 싶을 때는 UDP(User Datagram Protocol)를 사용.
  • UDP는 데이터를 보내면 그것으로 끝이므로 신뢰성은 없지만 확인 응답과 같은 절차를 생략할 수 있으므로 통신의 신속성을 높임.
    • 순차 전송 X, 흐름 제어 X, 혼잡 제어X, 3 way-handshake X
    • 패킷을 순차적으로 보내더라도 이 패킷들은 서로 다른 통신 선로를 통해 전달될 수 있음.
    • 최악의 경우 잘못된 선로로 전송되어 유실될 수도 있음.
    • 패킷이 유실이나 변조가 되어도 재전송을 하지 않음.
  • UDP는 전송계층의 비연결 지향적 프로토콜.
    • 데이터를 주고받을 때 연결 절차를 거치지 않고 발신자가 일방적으로 데이터를 발신하는 방식.
  • VoIP(Voice over IP)나 시간 동기, 영상 스트리밍 등과 같이 무엇보다 속도를 필요로 하는 서비스가 사용 중.

UDP 헤더

notion image
 

🤔 UDP의 단점

  • 데이터의 신뢰성이 없음.
  • 의미있는 서버를 구축하기위해서는 일일이 패킷을 관리해주어야 함.
 

🤩 결론

  • TCP, UDP의 특성을 파악하고 상황에 따라 적절한 프로토콜을 사용하자.
  • TCP, UDP의 헤더에 대해 파악하고 성능 개선에 이용하자.
 
 
 
참고자료 :
[Network] TCP / UDP의 개념과 특징, 차이점
[10분 테코톡] 👨‍🏫르윈의 TCP UDP
JavaScript Socket Programming Examples