programing

C - 직렬화 기술

stoneblock 2023. 7. 28. 21:45

C - 직렬화 기술

네트워크를 통해 전송할 데이터를 직렬화하기 위해 코드를 작성하고 있습니다.현재 저는 다음과 같은 기본 절차를 사용합니다.

  1. 을 생성합니다.void*완충제
  2. 다음과 같은 모든 바이트 순서 지정 작업 적용hton네트워크를 통해 전송할 데이터의 패밀리
  3. 사용하다memcpy메모리를 버퍼에 복사합니다.
  4. 네트워크를 통해 메모리 전송

문제는 다양한 데이터 구조(종종 무효* 데이터가 포함되어 있어 바이트 순서를 신경 쓸 필요가 있는지 여부를 알 수 없음)에서 코드가 각 데이터 구조에 매우 특정한 직렬화 코드로 인해 매우 비대해지고 전혀 재사용할 수 없다는 것입니다.

이것을 더 쉽게/ 덜 추하게 만드는 C의 좋은 직렬화 기술은 무엇입니까?

-

참고: 특정 프로토콜에 묶여 있기 때문에 데이터를 직렬화하는 방법을 자유롭게 선택할 수 없습니다.

각 데이터 구조에 대해 serialize_X 함수(여기서 X는 구조 이름)를 사용하여 X에 대한 포인터와 불투명 버퍼 구조에 대한 포인터를 가져오고 적절한 serializing 함수를 호출합니다.버퍼에 쓰고 출력 인덱스를 업데이트하는 serialize_int와 같은 기본 요소를 제공해야 합니다.원시 요소는 reserve_space(N)와 같은 것을 호출해야 합니다. 여기서 N은 데이터를 쓰기 전에 필요한 바이트 수입니다.reserve_space()는 void* 버퍼를 재할당하여 최소 현재 크기에 N바이트를 더한 크기로 만듭니다.이를 가능하게 하려면 버퍼 구조에 실제 데이터에 대한 포인터, 다음 바이트를 쓸 인덱스(출력 인덱스) 및 데이터에 할당된 크기가 포함되어야 합니다.이 시스템에서 모든 serialize_X 함수는 다음과 같이 매우 간단해야 합니다.

struct X {
    int n, m;
    char *string;
}

void serialize_X(struct X *x, struct Buffer *output) {
    serialize_int(x->n, output);
    serialize_int(x->m, output);
    serialize_string(x->string, output);
}

프레임워크 코드는 다음과 같습니다.

#define INITIAL_SIZE 32

struct Buffer {
    void *data;
    size_t next;
    size_t size;
}

struct Buffer *new_buffer() {
    struct Buffer *b = malloc(sizeof(Buffer));

    b->data = malloc(INITIAL_SIZE);
    b->size = INITIAL_SIZE;
    b->next = 0;
    
    return b;
}

void reserve_space(Buffer *b, size_t bytes) {
    if((b->next + bytes) > b->size) {
        /* double size to enforce O(lg N) reallocs */
        b->data = realloc(b->data, b->size * 2);
        b->size *= 2;
    }
}

이를 통해 필요한 serialize_() 함수를 모두 구현하는 것은 매우 간단할 것입니다.

편집: 예:

void serialize_int(int x, Buffer *b) {
    /* assume int == long; how can this be done better? */
    x = htonl(x);

    reserve_space(b, sizeof(int));

    memcpy(((char *)b->data) + b->next, &x, sizeof(int));
    b->next += sizeof(int);
}

편집: 또한 내 코드에 잠재적인 버그가 있습니다.오류 처리를 위한 규정도 없고 완료 후 버퍼를 해제할 수 있는 기능도 없으므로 사용자가 직접 이 작업을 수행해야 합니다.저는 제가 사용할 기본 아키텍처에 대한 시연을 하고 있었습니다.

직렬화를 직접 구현하려고 하지는 마십시오.수많은 작업이 수행되었으며 기존 솔루션을 사용해야 합니다. 예: protobfs: https://github.com/protobuf-c/protobuf-c

또한 다른 많은 프로그래밍 언어와 호환되는 장점이 있습니다.

저는 도서관을 이용하는 것을 제안합니다.

저는 기존 도서관이 마음에 들지 않아 우리의 삶을 편하게 하기 위해 빈 도서관을 만들었습니다.

다음은 사용 예입니다.

  binn *obj;

  // create a new object
  obj = binn_object();

  // add values to it
  binn_object_set_int32(obj, "id", 123);
  binn_object_set_str(obj, "name", "Samsung Galaxy Charger");
  binn_object_set_double(obj, "price", 12.50);
  binn_object_set_blob(obj, "picture", picptr, piclen);

  // send over the network
  send(sock, binn_ptr(obj), binn_size(obj));

  // release the buffer
  binn_free(obj);

프로토콜 제약 조건이 무엇인지 알면 도움이 되지만 일반적으로 사용자의 옵션은 상당히 제한적입니다.데이터가 각 구조체에 대해 (구조체)의 바이트 배열 크기를 결합할 수 있는 정도라면 일을 단순화할 수 있지만, 설명에 따르면 포인터를 전송하는 경우(보이드 * 데이터를 언급함) 수신기에서 해당 포인트가 유효할 가능성이 매우 낮습니다.데이터가 메모리의 동일한 위치에 나타나는 이유는 무엇입니까?

"C" 프로그램의 경우, "자동" 직렬화를 위한 좋은 옵션이 많지 않은 경우."포기"하기 전에 SUNRPC 패키지(rpcgen 및 친구)를 검토할 것을 제안합니다.다음을 포함됩니다.

  • 데이터 구조를 설명하는 "XDR" 언어(기본적으로 "C"의 하위 집합)인 사용자 정의 형식입니다.
  • RPC 생성 - 직렬화의 클라이언트 및 서버 측을 자동으로 생성할 수 있습니다.
  • 거의 모든 유닉스 환경과 함께 제공되는 런타임 라이브러리.

프로토콜과 코드에는 인터넷 표준이 있습니다.

이 도서관은 당신을 도울 수 있습니다.https://github.com/souzomain/Packer

그것은 사용하기 쉽고 코드는 공부하기에 깨끗합니다.

사용 예:

PPACKER protocol = packer_init();
packer_add_data(protocol, yourstructure, sizeof(yourstructure));
send(fd, protocol->buffer, protocol->offset, 0);
packer_free(protocol);

언급URL : https://stackoverflow.com/questions/6002528/c-serialization-techniques