티스토리 뷰

728x90

프로젝트에서 Netty 기반의 TCP 서버를 개발하던 중, 특정 상황에서 데이터 처리가 예상과 다르게 작동하는 문제를 겪었습니다. 클라이언트가 데이터를 전송했지만 서버에서 이를 처리하려고 할 때 데이터 부족 오류가 발생하거나, 패킷 단편화(Fragmentation) 문제가 원인임을 알게 되었습니다.

TCP의 특성과 패킷 단편화 문제

TCP는 스트림 기반 프로토콜로 데이터를 전송하기 때문에, 데이터를 송신한 단위(패킷)가 수신 측에서 동일한 단위로 도착한다고 보장하지 않습니다. 이로 인해 발생할 수 있는 두 가지 주요 현상은 다음과 같습니다:

  1. 패킷 단편화 (Fragmentation):
    클라이언트가 한 번에 보낸 데이터가 네트워크 경로에서 여러 조각으로 나뉘어 수신될 수 있습니다.
  2. 패킷 합쳐짐 (Coalescing):
    클라이언트가 보낸 여러 데이터가 네트워크 드라이버 수준에서 합쳐져 한 번에 도착할 수 있습니다.

TCP 데이터 처리에서 Netty의 역할

Netty는 이러한 TCP의 특성에 대응하기 위해 누적 버퍼링(cumulative buffering) 메커니즘을 제공합니다. Netty는 ByteBuf를 통해 데이터를 누적 관리하고, 사용자가 정의한 디코더를 통해 데이터의 경계(패킷의 끝)를 감지합니다.

Netty의 디코더를 사용하면 다음과 같은 방식으로 데이터를 처리할 수 있습니다:

  • 데이터가 부족하면 처리하지 않고 대기합니다.
  • 데이터가 충분히 누적되면 패킷을 읽고 처리합니다.

Netty를 활용한 데이터 누적 처리

TCP 단편화나 합쳐짐 문제를 해결하기 위해 Netty에서 데이터를 처리하는 예제를 살펴보겠습니다.

패킷 구조

HEADER (2 bytes) | VERSION (1 byte) | LENGTH (4 bytes) | OPCODE (1 byte) | DATA_FIELD (N bytes)
  • LENGTH: 패킷의 전체 크기를 나타내며, 여기에는 OPCODEDATA_FIELD의 크기가 포함됩니다.

Netty 디코더 구현 (Java)

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;

public class PacketDecoder extends ByteToMessageDecoder {

    private int LENGTH = -1;

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 1. 헤더와 길이 정보 읽기
        if (LENGTH == -1 && in.readableBytes() >= 7) { // HEADER(2) + VERSION(1) + LENGTH(4) + OPCODE(1)
            in.readShort();        // HEADER
            in.readByte();         // VERSION
            LENGTH = in.readInt(); // LENGTH
            in.readByte();         // OPCODE
        }

        // 2. 데이터 부족 확인
        if (LENGTH <= 0 || in.readableBytes() < LENGTH - 1) { // LENGTH - OPCODE 크기 확인
            return; // 데이터 부족 시 대기
        }

        // 3. 데이터 프레임 읽기
        byte[] dataField = new byte[LENGTH - 1];
        in.readBytes(dataField);

        // 4. 패킷 생성 및 전달
        Packet packet = new Packet(LENGTH, dataField);
        out.add(packet);

        // 5. 상태 초기화
        LENGTH = -1;
    }
}

class Packet {
    private final int length;
    private final byte[] dataField;

    public Packet(int length, byte[] dataField) {
        this.length = length;
        this.dataField = dataField;
    }

    @Override
    public String toString() {
        return "Packet{" +
                "length=" + length +
                ", dataField=" + new String(dataField) +
                '}';
    }
}

데이터 누적 처리 과정 시각화

Netty의 누적 버퍼링을 가시적으로 설명하기 위해 다음과 같은 데이터를 예로 들어 보겠습니다.

입력 데이터

[00 01] [01] [00 00 00 0A] [05] [41 42 43 44 45] [46 47 48 49 4A]

처리 과정

첫 번째 청크 수신

[00 01] [01] [00 00 00 0A] [05] [41 42]
  • HEADER, VERSION, LENGTH, OPCODE를 읽고, DATA_FIELD 일부만 수신.
  • LENGTH - 1 = 9, 현재 DATA_FIELD 크기: 2/9

두 번째 청크 수신

[43 44 45 46]
  • DATA_FIELD 추가.
  • 현재 DATA_FIELD 크기: 6/9

세 번째 청크 수신

[47 48 49 4A]
  • DATA_FIELD 완성.
  • 현재 DATA_FIELD 크기: 9/9

Netty 내부 동작과 관계

  1. Netty의 버퍼 관리:
    • ByteBuf는 Netty가 TCP 스트림의 특성을 처리하기 위해 제공하는 핵심 클래스입니다.
    • 데이터가 부족하면 decode() 메서드를 종료하지만, Netty는 이미 수신된 데이터를 자동으로 누적 관리합니다.
  2. 데이터 부족 처리:
    • return은 현재 데이터를 처리하지 않고 종료하겠다는 의미입니다.
    • 새로운 데이터가 들어오면 Netty가 decode() 메서드를 다시 호출합니다.
  3. 누적 버퍼링을 위한 상태 관리:
    • LENGTH를 상태 변수로 관리하여, 헤더를 읽은 이후에도 누적된 데이터를 바탕으로 데이터 처리 조건을 판단합니다.

누적 처리의 장점

  1. 데이터 손실 방지:
    • Netty는 부족한 데이터를 자동으로 누적 관리하므로, 데이터가 완전하지 않더라도 이후 데이터를 기다릴 수 있습니다.
  2. TCP 특성에 유연하게 대응:
    • TCP의 단편화와 합쳐짐 문제를 효과적으로 처리합니다.
  3. 구현의 간결성:
    • Netty의 디코더는 개발자가 누적 버퍼를 직접 관리하지 않아도 되도록 설계되어 있습니다.

참고

https://medium.com/daangn/%ED%99%95%EC%9E%A5%EC%84%B1-%EC%9E%88%EB%8A%94-tcp-%ED%86%B5%EC%8B%A0-%EC%8B%9C%EC%8A%A4%ED%85%9C-%EA%B5%AC%EC%B6%95%ED%95%98%EA%B8%B0-981c230cdc77

 

확장성 있는 TCP 통신 시스템 구축하기

Netty를 활용한 TCP Gateway 구축기

medium.com

https://okky.kr/questions/1001686

 

netty 통신에서 문자열 잘림 현상 | OKKY Q&A

현재 @Override protected void initChannel(SocketChannel arg0) { ChannelPipeline pipeline = arg0.pipeline(); pipeline.addLast(new StringDecoder(CharsetUtil.UTF_8)); pipeline.addLast(n

okky.kr

 

728x90
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함