• 티스토리 홈
  • 프로필사진
    소쩍소쩍이
  • 방명록
  • 공지사항
  • 태그
  • 블로그 관리
  • 글 작성
소쩍소쩍이
  • 프로필사진
    소쩍소쩍이
    • 분류 전체보기 (89)
      • 파이썬 (18)
        • 문제 및 예제 (8)
      • PySide6 (24)
        • Signal & Slot (6)
        • Layout (8)
        • Model & View (3)
        • File (4)
        • Resource (3)
      • Server - Client (17)
        • GUI 채팅 (1)
      • MySQL (4)
      • 리눅스 (5)
      • 아두이노 (0)
      • 일지 (20)
  • GitHub
  • 방문자 수
    • 전체:
    • 오늘:
    • 어제:
  • 최근 댓글
      등록된 댓글이 없습니다.
    # Home
    # 공지사항
    #
    # 태그
    # 검색결과
    # 방명록
    • 패킷 경계란?
      2026년 06월 25일
      • 소쩍소쩍이
      • 작성자
      • 2026.06.25.:07

      Stream 이해

      Stream을 이해하려면 먼저 비트와 바이트 개념을 알아야 한다.

      신호를 나타내는 최소 단위는 비트(bit)이다.

      정보의 기본 단위는 바이트(Byte)이다.

      8개의 비트를 묶으면 1바이트가 된다.

      영문자 한 글자(A)는 보통 1바이트로 저장된다.

       

      stream이란?

      스트림은 1바이트씩 순서대로 흘러가는 흐름을 뜻한다.

      파일 읽기 → 바이트가 앞에서부터 순서대로 흐른다
      키보드 입력 → 누른 글자가 순서대로 흐른다
      네트워크 → 보낸 바이트가 순서대로 흐른다
      TCP도 이와 같은 바이트 흐름 방식이다

       

      수도관에 비유하면 이해가 쉽다. 클라이언트가 메시지를 보내는 것은 수도관에 물을 붓는 것과 비슷하다.

       

      수도관 비유 TCP 소켓
      수도관에 물 붓기 send()로 데이터 흘려보내기
      반대편에서 물 받기 recv()로 흐르는 데이터 떠가기
      물이 이어져 흐름 바이트가 연속된 흐름으로 도착
      A물과 B물의 경계 구분 어려움 메시지 경계를 알 수 없음
      중간에 구분선 넣기 \n 같은 구분자 삽입

       

      Buffer 이해

      send()와 recv()는 단순히 메시지를 하나씩 주고받는 함수가 아니다. 실제로는 바이트 흐름과 버퍼를 이용한다.

      send()는 전달한 바이트를 스트림에 흘려보내는 작업이고, recv()는 스트림에서 도착한 바이트 일부를 읽어가는 작업이다.

       

      코드 실제 의미
      recv(1024) 최대 1024바이트까지 읽는다. 메시지 1개를 의미하는 것이 아니다
      recv() 반환값 현재 수신 버퍼에 있는 만큼 반환한다
      결과의 단위 메시지 하나일 수도 있고, 여러 개일 수도 있고, 메시지 일부일 수도 있다

       

      송신 버퍼와 수신 버퍼

      send()를 호출한다고 데이터가 바로 상대에게 날아가는 것은 아니다. 먼저 운영체제의 송신 버퍼에 복사되고, 커널이 백그라운드에서 적절한 크기로 잘라 전송한다.

      반대로 도착한 바이트는 수신 버퍼에 순서대로 쌓이고, recv()가 그 버퍼에서 읽어간다.

      송신 쪽:
      send() → 커널 송신 버퍼에 복사 → 커널이 잘라서 전송 → ACK 받으면 버퍼에서 제거

      수신 쪽:
      도착한 바이트 → 커널 수신 버퍼에 순서대로 쌓임 → recv()가 읽어 감

       

      핵심
      얼마씩 잘라 보내는지, 얼마씩 읽는지를 우리가 직접 정하지 않는다.
      그래서 send() 횟수와 recv() 횟수가 서로 맞지 않을 수 있다.

       

      버퍼는 데이터를 처리할 때까지 임시로 저장하는 공간이다.

       

      TCP와 Application 책임 이해

      애플리케이션 책임 구간과 소켓

      우리는 버퍼를 직접 만들거나 관리하지 않는다.

      TCP가 책임지는 순서 보장, 재전송 등은 매우 복잡한 작업이기 때문에 운영체제가 처리한다. 우리는 send()와 recv()만 호출하면 되고, 그 아래에서 벌어지는 일은 직접 관리하지 않아도 된다.

       

      TCP가 보장하는 것과 보장하지 않는 것

      구분 내용
      TCP가 보장하는 것 같은 소켓에서 보낸 바이트의 순서, 수신 버퍼에 쌓이는 순서, 손실된 바이트 재전송
      TCP가 보장하지 않는 것 recv() 한 번이 읽는 단위, 메시지가 어디서 끝나는지에 대한 경계

       

      주의
      TCP는 순서를 지켜 주지만 메시지 경계는 지켜 주지 않는다.
      즉, "bbbbaaaa"처럼 순서가 뒤바뀌지는 않지만, "aaaabbbb"처럼 메시지가 붙어서 올 수는 있다.

       

      [ TCP가 책임지는 구간 ]
      send() → 송신 버퍼 → 네트워크 → 수신 버퍼
      순서 보장, 손실 시 재전송

      [ 애플리케이션이 책임지는 구간 ]
      수신 버퍼 → recv() → 의미 있는 단위로 자르기
      메시지 경계 처리는 여기서 직접 해야 한다

       

      TCP는 어떻게 통신하나

       

      메시지 경계 문제를 직접 확인

      메시지 경계 문제는 크게 두 가지 모습으로 나타난다. 메시지가 붙어 도착하거나, 하나의 메시지가 여러 조각으로 나뉘어 도착할 수 있다.

      JSON 메시지에서는 이 문제가 더 분명하게 보인다.

      {"type":"chat","content":"A"}{"type":"chat","content":"B"}

      이렇게 객체 두 개가 붙어 오면 한 번에 해석하기 어렵다.

      반대로 메시지 하나가 여러 조각으로 나뉘어 오기도 한다.

      클라이언트가 보낸 메시지:
      {"type":"chat","content":"안녕하세요"}
      
      서버가 받은 조각:
      recv() 1회 → {"type":"chat",
      recv() 2회 → "content":"안녕하세요"}

      두 상황 모두 경계를 알려주는 표시가 없기 때문에 발생한다.

       

      socketpair()로 직접 재현

      📄 socketpair() 재현 코드
      import socket
      
      server, client = socket.socketpair()   # 네트워크 없이 연결된 두 소켓을 한 번에 만든다
      
      client.send(b"aaaa")                    # 첫 번째 메시지를 흘려보낸다
      client.send(b"bbbb")                    # 두 번째 메시지를 이어서 흘려보낸다
      
      data = server.recv(1024)                # 최대 1024바이트까지, recv()는 단 한 번만 호출
      print(data)                             # 출력 확인
      
      server.close()                          # 소켓 닫기
      client.close()

       

      실행 결과는 아래처럼 두 메시지가 붙어서 도착할 수 있다.

      b'aaaabbbb'

      즉, send()를 두 번 했다고 해서 recv()도 반드시 두 번으로 나뉘어 받는 것은 아니다.

       

      경계 처리 방법

      고정 크기 방식

      모든 메시지를 항상 같은 크기로 맞춰 보내는 방식이다. 받는 쪽은 정해진 크기만큼 읽으면 되므로 경계 고민이 사라진다.

      항상 64바이트씩 전송
      "안녕하세요" + 빈 공간으로 64바이트 채움
      받는 쪽은 64바이트씩 읽기

      구현이 가장 단순하지만 빈 공간 낭비가 생기고, 정해진 크기를 넘는 데이터는 보낼 수 없다. 주로 센서나 아두이노처럼 데이터 크기가 일정한 임베디드 환경에서 사용한다.

       

      구분자 방식

      메시지 끝에 특별한 문자를 붙여 경계를 표시하는 방식이다. 받는 쪽은 그 문자를 기준으로 잘라 메시지를 나눈다.

      {"type":"chat","content":"A"}\n{"type":"chat","content":"B"}\n

      \n 기준으로 자르면 메시지 2개로 나눌 수 있다.

      구현이 단순해 텍스트 채팅에 잘 맞지만, 메시지 내용 안에 구분자와 같은 문자가 들어가면 경계가 깨질 수 있다.

       

      길이 헤더 방식

      메시지 본문 앞에 "이 메시지는 몇 바이트다"라는 길이 정보를 먼저 붙이는 방식이다. 받는 쪽은 길이를 먼저 읽고, 그 길이만큼 정확히 읽어 메시지를 완성한다.

      [type][length][data]
      예: length=32 → 본문 32바이트를 정확히 읽어서 한 메시지로 완성

      구분자에 의존하지 않으므로 이미지나 파일 같은 바이너리 데이터도 안전하게 다룰 수 있다. 하지만 구현은 가장 복잡하다. 실무 프로토콜과 파일 전송에 자주 사용된다.

       

      방식 장점 단점 주로 쓰는 곳
      고정 크기 구현이 단순하고 경계 문제가 없다 빈 공간 낭비, 크기 초과 불가 임베디드, 센서, 아두이노
      구분자 구현이 단순하다 텍스트 전용, 내용에 구분자 포함 시 문제 가능 텍스트 채팅
      길이 헤더 바이너리 포함 모든 타입 처리 가능 구현이 가장 복잡하다 파일·이미지 전송, 실무 프로토콜

       

      자주 하는 오해

      오해 올바른 정리
      send() 한 번이면 recv() 한 번으로 정확히 받는다 TCP는 메시지 단위가 아니라 바이트 흐름이다. 메시지가 붙거나 나뉘어 도착할 수 있다
      recv(1024)가 메시지 1024개를 받는다 1024는 개수가 아니라 바이트 수다. 최대 1024바이트까지 읽는다는 뜻이다
      JSON으로 바꾸면 경계 문제가 자동으로 해결된다 JSON은 데이터 구조일 뿐, 네트워크 경계를 알려 주지 않는다. 경계 규칙은 따로 필요하다
      메시지가 짧으면 항상 안전하다 짧은 메시지도 연속으로 보내면 붙을 수 있다. 크기와 무관하게 경계 규칙이 필요하다
      순서가 뒤바뀌어 도착할 수도 있다 같은 소켓에서는 순서가 보장된다. 뒤바뀌지는 않고, 경계가 어긋날 뿐이다

       

      정리
      TCP는 데이터를 메시지 단위가 아니라 바이트 흐름으로 처리한다.

      순서는 TCP가 보장하지만, 메시지가 어디서 끝나는지에 대한 경계는 보장하지 않는다.

      따라서 채팅 프로그램에서는 \n 같은 구분자를 붙이거나, 길이 헤더처럼 별도의 규칙을 만들어 메시지 경계를 직접 처리해야 한다.

      'Server - Client' 카테고리의 다른 글

      패킷 경계와 메시지 구분 처리  (0) 2026.06.25
      JSON 기반 메시지 타입 설계  (0) 2026.06.23
      왜 메시지 규칙이 필요한가  (0) 2026.06.23
      전체 채팅 브로드캐스팅  (0) 2026.06.23
      접속자 목록 관리  (0) 2026.06.23
      다음글
      다음 글이 없습니다.
      이전글
      이전 글이 없습니다.
      댓글
    조회된 결과가 없습니다.
    스킨 업데이트 안내
    현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
    ("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)
    목차
    표시할 목차가 없습니다.
      • 안녕하세요
      • 감사해요
      • 잘있어요

      티스토리툴바