직렬화 이해


38

저는 소프트웨어 엔지니어이며 일부 동료들과 토론을 한 후 개념 직렬화에 대해 잘 이해하지 못했습니다. 내가 이해하는 바와 같이, 직렬화는 OOP의 객체와 같은 일부 엔티티를 바이트 시퀀스로 변환하는 프로세스이므로, 상기 엔티티는 후속 액세스를 위해 저장되거나 전송 될 수있다 ( "직렬화"프로세스).

내가 가진 문제는 모든 변수 (기본 요소 int또는 복합 객체 와 같은 )가 이미 바이트 시퀀스로 표현 되지 않았 습니까? (물론 레지스터, 메모리, 디스크 등에 저장되어 있기 때문에)

그렇다면 직렬화가 그 토픽 인 이유는 무엇입니까? 변수를 직렬화하려면이 바이트를 메모리로 가져 와서 파일에 쓸 수 없습니까? 내가 놓친 복잡한 점은 무엇입니까?


21
연속 된 객체의 경우 직렬화가 쉽지 않을 수 있습니다 . 객체 값이 포인터 그래프 로 표시 되면 특히 그래프에 루프가있는 경우 상황이 훨씬 까다로워집니다.
chi

1
@chi : 첫 번째 문장은 연속성이 부적절하다는 점에서 약간 오해의 소지가 있습니다. 메모리에서 연속적으로 발생하는 그래프가있을 수 있으며 여전히 (a) 실제로 연속되어 있음을 감지하고 (b) 내부 포인터를 수정해야하기 때문에 직렬화에 도움이되지 않는 그래프가있을 수 있습니다. 나는 당신이 말한 것의 두 번째 부분을 말하고 싶습니다.
Mehrdad

@ Mehrdad 나는 당신이 언급 한 이유로 내 의견이 완전히 정확하지 않다는 데 동의합니다. 아마도 포인터가없는 / 포인터 사용은 더 나은 구별입니다 (완전히 정확하지 않더라도)
chi

7
또한 하드웨어 표현에 대해 걱정해야합니다. 4 bytesPDP-11 에서 int 를 직렬화 한 다음 동일한 4 바이트를 내 맥북의 메모리로 읽으려고 시도하면 엔디안 때문에 같은 숫자가 아닙니다. 따라서 해독 할 수있는 표현으로 데이터를 정규화해야합니다 (직렬화). 데이터를 직렬화하는 방법에는 사람 / 기계가 읽을 수있는 속도 / 유연성 상충 관계도 있습니다.
Martin York

많은 탐색 속성이 포함 된 Entity Framework를 사용하는 경우 어떻게됩니까? 어떤 경우에는 탐색 특성을 직렬화 할 수도 있지만 직렬화 된 상위 오브젝트에있는 ID를 기반으로 데이터베이스에서 실제 오브젝트를 다시로드하기 때문에 탐색 특성을 널 (NULL)로 두십시오. 이것은 하나의 예일뿐입니다. 많이있다.
ErikE

답변:


40

복잡한 데이터 구조가있는 경우 일반적으로 메모리에 표현이 메모리 전체에 흩어질 수 있습니다. (예를 들어, 이진 트리를 생각하십시오.)

반대로, 디스크에 쓰려고 할 때 연속적으로 바이트가 연속적으로 표시되는 것을 원할 것입니다. 그것이 직렬화가 당신을 위해하는 일입니다.


27

내가 가진 문제는 모든 변수 (int 또는 복합 객체와 같은 기본 요소)가 이미 바이트 시퀀스로 표시되지 않습니까? (물론 레지스터, 메모리, 디스크 등에 저장되어 있기 때문에)

그렇다면 직렬화가 그 토픽 인 이유는 무엇입니까? 변수를 직렬화하려면이 바이트를 메모리로 가져 와서 파일에 쓸 수 없습니까? 내가 놓친 복잡한 점은 무엇입니까?

다음과 같이 정의 된 노드가있는 C의 객체 그래프를 고려하십시오.

struct Node {
    struct Node* parent;
    struct Node* someChild;
    struct Node* anotherLink;

    int value;
    char* label;
};

//

struct Node nodes[10] = {0};
nodes[5].parent = nodes[0];
nodes[0].someChild = calloc( 1, sizeof(struct Node) );
nodes[5].anotherLink = nodes[3];
for( size_t i = 3; i < 7; i++ ) {
    nodes[i].anotherLink = calloc( 1, sizeof(struct Node) );
}

런타임에 전체 객체 Node그래프가 메모리 공간에 흩어져 있으며 여러 노드에서 동일한 노드를 가리킬 수 있습니다.

메모리를 파일 / 스트림 / 디스크로 덤프 할 수 없으며 메모리 주소 인 포인터 값을 직렬화 해제 할 수 없기 때문에 직렬화로 호출 할 수 없습니다 (덤프를 다시로드 할 때 해당 메모리 위치가 이미 점유되어 있기 때문에) 메모리에). 단순히 메모리를 덤핑하는 또 다른 문제는 모든 종류의 관련없는 데이터와 사용되지 않은 공간을 저장하게된다는 것입니다. x86에서 프로세스는 최대 4GiB의 메모리 공간을 가지며 OS 또는 MMU는 실제로 어떤 메모리인지에 대한 일반적인 아이디어 만 갖습니다. 의미 있는지 아닌지 (프로세스에 할당 된 메모리 페이지를 기반으로) Notepad.exe텍스트 파일을 저장할 때마다 4GB의 원시 바이트를 디스크에 덤프하면 약간 낭비됩니다.

또 다른 문제는 버전 관리와 관련이 Node있습니다. 1 일에 그래프 를 직렬화 한 다음 2 일에 다른 필드 Node(예 : 다른 포인터 값 또는 기본 값)를 추가 한 다음 3 일에 파일을 직렬화 해제 하면 어떻게됩니까 ? 1 일?

엔디안과 같은 다른 것들도 고려해야합니다. MacOS와 IBM / Windows / PC 파일이 1980 년대와 1990 년대에 같은 프로그램 (Word, Photoshop 등)에 의해 만들어졌지만 x86 / PC 멀티 바이트 정수 값 때문 이었음에도 불구하고 서로 호환되지 않는 주된 이유 중 하나 는 리틀 엔디안 순서로 저장되었지만 Mac에서는 빅 엔디안 순서로 저장되었습니다. 소프트웨어는 크로스 플랫폼 이식성을 염두에두고 제작되지 않았습니다. 오늘날 개발자 교육이 개선되고 점점 더 이기종 컴퓨팅 환경이 개선되어 상황이 개선되었습니다.


2
프로세스 메모리 공간에 모든 것을 버리는 것은 보안상의 이유로 끔찍할 것입니다. 프로그램의 밤은 1) 일부 공개 데이터와 2) 암호, 비밀 논스 또는 개인 키를 모두 기억합니다. 전자를 직렬화 할 때, 전자에 대한 정보를 공개하고 싶지 않습니다.
chi

8
이 주제에 대한 매우 흥미로운 메모 : Microsoft Office 파일 형식이 왜 그렇게 복잡한가?
눈에 띄는

15

까다로운 것은 실제로 " 직렬화 "라는 단어 자체에 이미 설명되어 있습니다.

문제는 기본적으로 어떻게 임의의 복잡한 객체의 임의의 복잡한 상호 연결된 순환 지향 그래프를 선형 바이트 시퀀스로 나타낼 수 있습니까?

생각해보십시오. 선형 시퀀스는 모든 정점이 정확히 하나의 수신 및 발신 에지를 갖는 퇴행 지향 그래프와 비슷합니다 (수신 에지가없는 "첫 번째 정점"및 발신 에지가없는 "마지막 정점"제외). . 그리고 바이트 는 분명히 객체 보다 덜 복잡 합니다 .

따라서 우리가 임의로 복잡한 그래프에서 훨씬 더 제한된 "그래프"(실제로 단지 목록)로 이동하고 임의로 복잡한 객체에서 간단한 바이트로 정보 잃어 버리면 정보 잃어 버리게됩니다. "어떤"정보를 어떤 식 으로든 인코딩하지 마십시오. 그것이 바로 직렬화가하는 일입니다. 복잡한 정보를 간단한 선형 형식으로 인코딩하십시오.

YAML 에 대해 잘 알고 있다면 직렬화에서 "동일한 객체가 다른 위치에 나타날 수 있습니다"라는 아이디어를 나타낼 수 있는 앵커별칭 기능을 살펴볼 수 있습니다.

예를 들어 다음 그래프가있는 경우 :

A → B → D
↓       ↑
C ––––––+

다음과 같이 YAML의 선형 경로 목록으로 표시 할 수 있습니다.

- [&A A, B, &D D]
- [*A, C, *D]

인접 목록 또는 인접 행렬 또는 첫 번째 요소가 노드 세트이고 두 번째 요소가 노드 쌍 세트 인 쌍으로 표시 할 수도 있지만 이러한 모든 표현에는 다음이 있어야합니다. 기존 노드, 즉 일반적으로 파일이나 네트워크 스트림에없는 포인터 와 같은 노드 를 앞뒤로 참조하는 방법 . 결국에는 바이트 만 있으면됩니다.

(BTW는 위의 YAML 텍스트 파일 자체도 "직렬화"되어야 함을 의미합니다. 즉, 다양한 문자 인코딩 및 유니 코드 전송 형식이 사용됩니다. 텍스트 파일이 이미 직렬이기 때문에 인코딩 만 엄격하게 "직렬화"되지 않습니다. / 코드 포인트의 선형 목록이지만 일부 유사점을 볼 수 있습니다.)


13

다른 답변은 이미 복잡한 객체 그래프를 다루고 있지만, 직렬화 프리미티브도 사소하지 않다는 점을 지적 할 가치가 있습니다.

구체적으로 C 기본 유형 이름을 사용하여 다음을 고려하십시오.

  1. 나는 직렬화한다 long. 얼마 후 나는 그것을 직렬화 해제하지만 ... 다른 플랫폼에서 지금 long은 내가 저장 한 int64_t것이 아닙니다 int32_t. 따라서 내가 저장하는 모든 유형의 정확한 크기에 대해 매우주의를 기울이거나 모든 필드의 유형과 크기를 설명하는 일부 메타 데이터를 저장해야합니다.

    다른 플랫폼 은 나중에 다시 컴파일 한 후에도 동일한 플랫폼 일 수 있습니다.

  2. 을 직렬화합니다 int32_t. 얼마 후 나는 그것을 직렬화 해제하지만 ... 다른 플랫폼에서, 지금은 가치가 손상되었습니다. 슬프게도 나는 빅 엔디안 플랫폼에 가치를 저장하고 리틀 엔디안 플랫폼에로드했습니다. 지금은 내 형식에 대한 규칙을 설정하거나 추가 할 필요가 어떤 / 각 파일 / 스트림의 endiannness을 설명하는 메타 데이터를. 물론 실제로 적절한 전환을 수행합니다.

  3. 문자열을 직렬화합니다. 이번에는 하나의 플랫폼 char과 UTF-8, 하나 wchar_t와 UTF-16을 사용합니다.

따라서 합리적인 품질의 직렬화는 연속 메모리의 프리미티브에서도 사소한 것이 아니라고 주장합니다. 인라인 메타 데이터로 문서화하거나 설명하는 데 필요한 인코딩 결정이 많이 있습니다.

객체 그래프는 그 위에 또 다른 복잡성을 추가합니다.


6

여러 측면이 있습니다.

동일한 프로그램에 의한 가독성

프로그램이 어떻게 든 데이터를 메모리에 바이트로 저장했습니다. 그러나 포인터가 작은 조각들 사이에서 앞뒤로 움직이면서 다른 레지스터에 임의로 흩어질 수 있습니다 [편집 : 언급 한 바와 같이 물리적으로 데이터는 데이터 레지스터보다 기본 메모리에있을 가능성이 높지만 포인터 문제를 제거하지는 않습니다] . 연결된 정수 목록을 생각해보십시오. 각 목록 요소는 완전히 다른 위치에 저장 될 수 있으며 목록을 함께 보유하는 모든 요소는 한 요소에서 다음 요소로의 포인터입니다. 해당 데이터를있는 그대로 가져와 같은 프로그램을 실행하는 다른 컴퓨터에 복사하려고하면 문제가 발생할 수 있습니다.

  1. 무엇보다도 데이터가 한 시스템에 저장된 주소를 등록하는 레지스터는 다른 시스템에서 완전히 다른 것으로 이미 사용될 수 있습니다 (누군가 찾아보기 스택 교환을하고 브라우저는 이미 모든 메모리를 먹었습니다). 따라서 단순히 레지스터를 재정의하면 브라우저를 사용하십시오. 따라서 두 번째 컴퓨터에서 사용 가능한 주소에 맞게 구조에서 포인터를 다시 정렬해야합니다. 같은 컴퓨터에서 나중에 데이터를 다시로드하려고 할 때도 동일한 문제가 발생합니다.
  2. 외부 구성 요소가 구조를 가리 키거나 구조에 외부 데이터에 대한 포인터가 있으면 전송하지 않은 경우는 어떻게됩니까? 모든 곳에서 Segfaults! 이것은 디버깅 악몽이 될 것입니다.

다른 프로그램에 의한 가독성

데이터를 맞추기 위해 다른 컴퓨터에 올바른 주소 만 할당한다고 가정 해 봅시다. 데이터가 해당 컴퓨터의 별도 프로그램 (다른 언어)으로 처리되는 경우 해당 프로그램의 데이터에 대한 기본 이해가 완전히 다를 수 있습니다. 포인터가있는 C ++ 객체가 있지만 대상 언어가 해당 레벨의 포인터를 지원하지 않는다고 가정 해보십시오. 다시 말하지만, 두 번째 프로그램에서 해당 데이터를 처리 할 수있는 확실한 방법이 없습니다. 메모리에 이진 데이터가 생길 수 있지만 데이터를 감싸는 추가 코드를 작성해야하며 대상 언어가 작동 할 수있는 코드로 변환해야합니다. 역 직렬화처럼 들리는데, 시작점이 이제 주 메모리 주변에 흩어져있는 이상한 물체라는 것입니다. 소스 언어마다 다릅니다. 구조가 잘 정의 된 파일 대신. 물론 포인터가 포함 된 이진 파일을 직접 해석하려고하면 다른 언어가 메모리 내 데이터를 나타낼 수있는 모든 가능한 방법에 대해 파서를 작성해야합니다.

인간의 가독성

웹 기반 직렬화 (xml, json)를위한 가장 유명한 최신 직렬화 언어 중 2 개는 사람이 쉽게 이해할 수 있습니다. goo의 이진 파일 대신 데이터를 읽는 프로그램이 없어도 데이터의 실제 구조와 내용이 명확합니다. 여기에는 여러 가지 장점이 있습니다.

  • 더 쉬운 디버깅-> 서비스 파이프 라인에 문제가있는 경우, 하나의 서비스에서 나오는 데이터를보고 이해가되는지 확인하십시오 (첫 번째 단계). 내보내기 인터페이스를 처음 작성할 때 데이터가 생각한 것처럼 보이는지 직접 확인할 수도 있습니다.
  • 보관 : 데이터를 순수 이진 구 더미로 가지고 있고이를 해석하려는 프로그램을 느슨하게하면 데이터가 느슨해집니다 (또는 실제로 무언가를 찾으려면 꽤 오랜 시간을 소비해야합니다). 직렬화 된 데이터를 사람이 읽을 수있는 경우 쉽게 아카이브로 사용하거나 새로운 프로그램에 대한 자신의 수입업자를 프로그램 할 수 있습니다
  • 이러한 방식으로 직렬화 된 데이터의 선언적 특성은 컴퓨터 시스템 및 하드웨어와 완전히 독립적이라는 의미입니다. 완전히 다른 방식으로 구성된 양자 컴퓨터에로드하거나 다른 사실로 외계인 AI를 감염시켜 우연히 다음 태양으로 날아갈 수 있습니다. 영화)

내 데이터는 아마도 레지스터가 아닌 주로 메인 메모리에 있습니다. 내 데이터가 레지스터에 맞는 경우 직렬화는 거의 문제가되지 않습니다. 레지스터가 무엇인지 잘못 이해했다고 생각합니다.
David Richerby

사실, 여기서 레지스터라는 용어를 너무 느슨하게 사용했습니다. 그러나 요점은 데이터에 자체 구성 요소를 식별하거나 다른 데이터를 참조하기 위해 주소 공간에 대한 포인터를 포함 할 수 있다는 것입니다. 메인 메모리의 물리적 레지스터인지 가상 주소인지는 중요하지 않습니다.
Frank Hopkins

아니요, "등록"이라는 용어를 완전히 잘못 사용했습니다. 레지스터를 호출하는 것은 실제 레지스터와 메모리 계층의 완전히 다른 부분에 있습니다.
David Richerby

6

다른 답변이 말한 것 외에도 :

때로는 순수한 데이터가 아닌 것을 직렬화하려고합니다.

예를 들어, 파일 핸들 또는 서버 연결을 생각하십시오. 파일 핸들 또는 소켓이이지만 int다음에 프로그램을 실행할 때는이 숫자가 의미가 없습니다. 이러한 것들에 대한 핸들이 포함 된 객체를 올바르게 다시 만들려면 파일을 다시 열고 연결을 다시 만들고 실패한 경우 수행 할 작업을 결정해야합니다.

요즘 많은 언어는 객체 내에 익명 함수 저장을 지원합니다 (예 : onBlah()Javascript 의 핸들러). 이러한 코드에는 일련의 추가 데이터에 대한 참조가 포함될 수 있기 때문에 까다로울 수 있습니다. (그리고 크로스 플랫폼 방식으로 코드를 직렬화하는 문제가 있습니다. 이는 해석 된 언어에서 더 쉽습니다.) 그럼에도 불구하고 언어의 일부만 지원 될 수는 있지만 여전히 유용 할 수 있습니다. 많은 직렬화 메커니즘이 코드를 직렬화하려고 시도하지만 serialize-javascript를 참조하십시오 .

개체를 직렬화하려고하지만 직렬화 메커니즘에서 지원하지 않는 개체가 포함 된 경우이 문제를 해결하는 방식으로 코드를 다시 작성해야합니다. 예를 들어, 한정된 수의 함수가있을 때 익명 함수 대신 열거 형을 사용할 수 있습니다.

종종 직렬화 된 데이터가 간결 해지기를 원합니다.

네트워크를 통해 데이터를 보내거나 디스크에 저장하는 경우 크기를 작게 유지하는 것이 중요 할 수 있습니다. 이를 달성하는 가장 쉬운 방법 중 하나는 재 구축 할 수있는 정보 (예 : 캐시, 해시 테이블 및 동일한 데이터의 대체 표현 삭제)를 버리는 것입니다.

물론 프로그래머는 저장할 내용과 버릴 내용을 수동으로 선택하고 개체를 다시 만들 때 항목을 다시 작성해야합니다.

게임 저장 행위에 대해 생각해보십시오. 객체는 그래픽 데이터, 사운드 데이터 및 기타 객체에 대한 많은 포인터를 포함 할 수 있습니다. 그러나이 대부분은 게임 데이터 파일에서로드 할 수 있으며 저장 파일에 저장할 필요는 없습니다. 그것을 버리는 것은 힘들 수 있으므로 종종 적은 것들이 남아 있습니다. 필자는 제 시간에 일부 저장 파일을 16 진수로 편집했으며 텍스트 항목 설명과 같이 명확하게 중복 된 데이터를 발견했습니다.

공간이 중요하지 않지만 가독성이 좋은 경우가 있습니다.이 경우 ASCII 형식 (JSON 또는 XML)을 대신 사용할 수 있습니다.


3

바이트 시퀀스가 ​​실제로 무엇인지 정의 해 봅시다. 바이트 시퀀스는 길이 라고하는 음이 아닌 정수 와 길이 가 0보다 작고 길이 보다 작은 정수 i 를 바이트 값 (0-255의 정수)에 매핑하는 임의의 함수 / 대응으로 구성됩니다 .

일반적인 프로그램에서 다루는 많은 객체는 실제로는 그 형태가 아닙니다. 왜냐하면 객체는 실제로 RAM의 다른 위치에있는 많은 다른 메모리 할당으로 구성되어 있으며 수백만 바이트의 물건으로 서로 분리 될 수 있기 때문입니다. 신경 쓰지 마 기본 연결 목록을 생각해보십시오. 목록의 각 노드는 바이트 시퀀스입니다. 그러나 노드는 컴퓨터 메모리의 서로 다른 위치에 있으며 포인터로 연결되어 있습니다. 또는 가변 길이 문자열에 대한 포인터가있는 간단한 구조체를 생각해보십시오.

데이터 구조를 일련의 바이트로 직렬화하려는 이유는 일반적으로 데이터 구조를 디스크에 저장하거나 다른 시스템 (예 : 네트워크)으로 보내려고하기 때문입니다. 디스크에 포인터를 저장하거나 다른 시스템으로 보내려고하면 해당 포인터를 읽는 프로그램에 사용 가능한 메모리 영역이 달라지기 때문에 쓸모가 없습니다.


1
이것이 시퀀스의 훌륭한 정의인지 확실하지 않습니다. 대부분의 사람들은 순서를 순서대로 정의 할 것입니다. 정의에 따르면 int seq(int i) { if (0 <= i < length) return i+1; else return -1;}시퀀스입니다. 그러면 디스크에 어떻게 저장합니까?
David Richerby

1
길이가 4이면 내용이 1, 2, 3, 4 인 4 바이트 파일을 저장합니다.
David Grayson

1
@DavidRicherby 그의 정의는 "일렬로 사물 라인"에 해당하며, 직관적 인 정의보다 수학적이고 정확한 정의입니다. 시퀀스를 가지려면 해당 함수 길이라는 다른 정수 가 필요하기 때문에 함수는 시퀀스가 ​​아닙니다 .
user253751

1
@FreshAir 내 요점은 시퀀스 가 1, 2, 3, 4, 5라는 것입니다. 제가 적어 둔 것은 함수 입니다. 함수는 시퀀스가 ​​아닙니다.
David Richerby

1
디스크에 함수를 작성하는 간단한 방법은 이미 제안한 방법입니다. 가능한 모든 입력에 대해 출력을 저장하십시오. 어쩌면 당신은 여전히 ​​그것을 얻지 못하지만 어떻게 말 해야할지 모르겠습니다. 임베디드 시스템에서 값 비싼 함수 sin를 룩업 테이블 (일련의 숫자 시퀀스)로 변환하는 것이 일반적이라는 것을 알고 있습니까? 귀하의 기능이 관심있는 입력의 기능과 동일하다는 것을 알고 있습니까? int seq(n) { int a[] = [1, 2, 3, 4]; return a[n]; } 이유는 정확히 내 4 바이트 파일이 부적절한 표현이라고 말할 수 있습니까?
David Grayson

2

복잡성은 데이터와 객체 자체의 복잡성을 반영합니다. 이러한 개체는 실제 개체이거나 컴퓨터 전용 개체 일 수 있습니다. 답은 이름입니다. 직렬화는 다차원 개체의 선형 표현입니다. 조각난 RAM 이외의 많은 문제가 있습니다.

12 5 차원 배열과 일부 프로그램 코드를 평면화 할 수 있으면 직렬화를 통해 컴퓨터간에 전체 컴퓨터 프로그램 (및 데이터)을 전송할 수도 있습니다. RMI / CORBA와 같은 분산 컴퓨팅 프로토콜은 직렬화를 사용하여 데이터와 프로그램을 전송합니다.

전화 요금 청구서를 고려하십시오. 모든 통화 (문자열 목록), 지불 할 금액 (정수) 및 국가로 구성된 단일 객체 일 수 있습니다. 또는 귀하의 전화 요금 청구서는 위의 내용 중 하나 일 수 있으며 귀하의 이름과 연결된 개별 항목 별 전화 통화로 구성 될 수 있습니다. 각각의 평평한 모양은 다르게 보일 것입니다. 전화 회사가 해당 버전의 소프트웨어를 어떻게 작성했는지와 객체 지향 데이터베이스가 결코 시작되지 않은 이유를 반영합니다.

구조의 일부는 전혀 메모리에 없을 수도 있습니다. 지연 캐싱이있는 경우 개체의 일부 부분은 디스크 파일 만 참조 할 수 있으며 해당 특정 개체의 해당 부분에 액세스 할 때만로드됩니다. 이것은 심각한 지속성 프레임 워크에서 일반적입니다. BLOB가 좋은 예입니다. Getty Images는 Fidel Castro의 거대한 수 메가 바이트 사진과 이미지 이름, 대여 비용 및 이미지 자체와 같은 일부 메타 데이터를 저장할 수 있습니다. 실제로 보지 않는 한 매 200MB 사진을 메모리에로드하지 않을 수 있습니다. 직렬화하면 전체 파일에 200MB 이상의 저장 공간이 필요합니다.

일부 개체는 전혀 직렬화 할 수 없습니다. Java 프로그래밍 영역에서는 그래픽 화면 또는 물리적 직렬 포트를 나타내는 프로그래밍 개체가있을 수 있습니다. 둘 중 하나를 직렬화하는 실제 개념은 없습니다. 네트워크를 통해 다른 사람에게 포트를 어떻게 보내시겠습니까?

비밀번호 / 암호화 키와 같은 일부는 저장하거나 전송해서는 안됩니다. 그것들은 (휘발성 / 일시적 등) 태그를 붙일 수 있고 직렬화 프로세스는 그것들을 건너 뛰지 만 RAM에 살 수 있습니다. 이 태그를 생략하면 암호화 키가 실수로 일반 ASCII로 전송 / 저장되는 방식입니다.

이것과 다른 답변이 복잡한 이유입니다.


2

내가 가진 문제는 모든 변수 (int 또는 복합 객체와 같은 기본 요소)가 이미 바이트 시퀀스로 표시되지 않습니까?

그렇습니다. 여기서 문제는 해당 바이트의 레이아웃입니다. 간단한 길이 int는 2, 4 또는 8 비트 일 수 있습니다. 크거나 작은 엔디안 일 수 있습니다. 부호없는, 1의 보수로 서명되거나 심지어 부정과 같은 매우 이국적인 비트 코딩으로 서명 될 수 있습니다.

int바이너리를 메모리에서 덤프하여 "직렬화"라고 부르는 경우 직렬화를 해제하려면 거의 전체 컴퓨터, 운영 체제 및 프로그램을 연결해야합니다. 또는 적어도 그들에 대한 정확한 설명.

그렇다면 직렬화가 그 토픽 인 이유는 무엇입니까? 변수를 직렬화하려면이 바이트를 메모리로 가져 와서 파일에 쓸 수 없습니까? 내가 놓친 복잡한 점은 무엇입니까?

간단한 객체의 직렬화는 일부 규칙에 따라 적어 둡니다. 이러한 규칙은 충분하고 항상 분명하지는 않습니다. 예를 들어 xs:integerin XML은 10 진법으로 작성되었습니다. 기본 16이 아니라 기본 9가 아니라 10입니다. 숨겨진 가정이 아니라 실제 규칙입니다. 이러한 규칙은 직렬화를 직렬화로 만듭니다. 때문에, 거의, 메모리에 프로그램의 비트 레이아웃에 대한 아무런 규정이 없다 .

그것은 단지 빙산의 일각이었습니다. 가장 간단한 프리미티브 시퀀스 인 C를 예로 들어 봅시다 struct. 당신은 그것을 생각할 수 있습니다

struct {
short width;
short height;
long count;
}

주어진 컴퓨터 + OS에 정의 된 메모리 레이아웃이 있습니까? 글쎄요. 현재 #pragma pack설정에 따라 컴파일러가 필드를 채 웁니다. 32 비트 컴파일의 기본 설정에서 둘 다 shorts4 바이트로 채워 지므로 struct실제로 메모리에 4 바이트의 3 개 필드가 있습니다. 따라서 이제는 short16 비트 길이 를 지정할 필요 가 없으며 1, 음수, 크거나 작은 엔디안을 보완하는 정수입니다. 또한 프로그램이 컴파일 된 구조 패킹 설정을 기록해야합니다.

그것은 일련의 규칙에 관한 것입니다. 규칙 세트를 만들고 고수하는 것입니다.

그런 다음 이러한 규칙을 확장하여 가변 길이 목록 또는 비선형 데이터와 같은 더 복잡한 구조를 수용하고 사람의 가독성, 버전 관리, 이전 버전과의 호환성 및 오류 수정 등과 같은 기능을 추가 int할 수 있습니다. 당신이 그것을 확실하게 다시 읽을 수있게하고 싶을뿐입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.