序列化和封送处理有什么区别?


Answers:


404

在远程过程调用的上下文中,封送处理和序列化是松散的同义词,但是从意图上来说在语义上有所不同。

特别地,封送处理是关于从此处获取参数,而序列化是关于向诸如字节流之类的原始形式复制结构化数据。从这个意义上讲,序列化是执行封送处理的一种方法,通常实现按值传递语义。

还可以通过引用将对象编组,在这种情况下,“在线”数据仅仅是原始对象的位置信息。但是,这样的对象可能仍然适合于值序列化。

正如@Bill所提到的,可能存在其他元数据,例如代码库位置甚至对象实现代码。


3
是否有一个单词表示同时进行序列化和反序列化?这些接口的接口需要一个名称。
拉菲

1
@raffian,您的意思是接口是由经历序列化和反序列化的对象实现的,还是由负责管理流程的对象实现的?我建议的关键词分别是“可序列化”和“格式化”。根据需要进行装饰I,大写更改等。
杰弗里·汉汀

@JeffreyHantin我的意思是负责管理流程的对象;我现在正在使用ISerializer,但这只是一半:)
raffian

6
在电信中,@ raffian,我们称为“ SerDes”或“ serdes”的序列化和反序列化的组件,根据喜好通常称为sir-dez或sir-deez。我想它的构造类似于“调制解调器”(即“调制器-解调器”)。
davidA

2
@naki是整个行业的-如果您查看高速FPGA数据表,他们会提到SERDES功能,尽管这些功能都相当现代,可以追溯到1990年代。Google NGrams建议它在1980年代变得更流行,尽管我确实在1970
davidA

207

两者都有一个共同点- 序列化对象。序列化用于传输对象或存储对象。但:

  • 序列化:序列化对象时,只有该对象内的成员数据才写入字节流;而不是实际实现该对象的代码。
  • 编组: 术语“编组”在我们谈论将对象传递给远程对象(RMI)时使用。在编组对象已序列化(成员数据已序列化)中+附加了代码库。

因此,序列化是编组的一部分。

CodeBase是一种信息,它告诉Object的接收者可以在哪里找到该对象的实现。任何认为它可能曾经将一个对象传递给另一个可能之前从未看过它的程序的程序,都必须设置代码库,以便接收方可以知道从哪里下载代码(如果它在本地没有可用的代码)。接收器将在反序列化对象时从其获取代码库,并从该位置加载代码。


45
+1定义CodeBase在这种情况下的含义
Omar Salem 2013年

2
无需序列化就可以封送处理。请参见Swing invokeAndWait和Forms Invoke,它们封送对UI线程的同步调用,而无需进行序列化。
杰弗里·汉汀

2
“不是实际实现该对象的代码”:这是否意味着类方法?或这是什么意思。你能解释一下吗?
Vishal Anand

2
你是什么意思the implementation of this object?你能不能给一个具体的例子SerializationMarshalling
Simin Jie '18

在某些情况下会发生不进行序列化的编组,例如函数调用在单个进程中的线程模型之间(例如,在共享线程池和单固定线程库之间)转移控制流时。这就是为什么我说它们在RPC中是松散的同义词。
Jeffrey Hantin

94

编组(计算机科学)维基百科文章中:

在Python标准库1中,术语“编组”被视为与“序列化”同义,但是在Java相关的RFC 2713中,术语不是同义的:

“封送”一个对象意味着以一种方式记录其状态和代码库,以便在“解组”被封送的对象时,可以通过自动加载该对象的类定义来获取原始对象的副本。您可以封送可序列化或远程的任何对象。封送就像序列化,只是封送还记录代码库。封送与序列化的不同之处在于,封送特别处理远程对象。(RFC 2713)

“序列化”对象意味着将其状态转换为字节流,以便可以将字节流转换回该对象的副本。

因此,编组除了将对象的状态保存外,还将其代码库保存在字节流中。


1
您的意思是对象,如果未序列化,则只能具有状态,不会有任何代码库,即无法调用其函数,它只是结构化的数据类型。而且,如果将同一对象编组,那么它将具有其代码库以及结构,并且一旦可以调用其功能?
2014年

11
“代码库”实际上不是“代码”。在“代码库的工作原理 ”(goo.gl/VOM2Ym)中,代码库非常简单地说明了使用RMI的远程类加载语义的程序如何找到新类。当对象的发送者序列化该对象以传输到另一个JVM时,它将使用称为代码库的信息来注释序列化的字节流。此信息告诉接收者可以在哪里找到此对象的实现。存储在代码库批注中的实际信息是URL列表,可以从中下载所需对象的类文件。
Giuseppe Bertone 2014年

2
@Neurone该定义特定于Jini和RMI。“代码库”是一个通用术语。en.wikipedia.org/wiki/Codebase
比尔·蜥蜴

2
@BilltheLizard是的,但是因为您在谈论Java中的封送处理,所以错误地说序列化和封送处理之间的区别是“封送除保存对象的状态外还保存了对象的代码”,这引发了bjan的问题。编组除对象状态外,还保存了“代码库”。
Giuseppe Bertone 2014年

19

我认为主要的区别是编组应该还涉及代码库。换句话说,您将无法将对象编组和解组为状态不同的类的实例。。

序列化只是意味着您可以存储对象并重新获得等效状态,即使它是另一个类的实例也是如此。

话虽如此,它们通常是同义词。


2
您的意思是说,对象(如果未序列化)只能具有状态,不会有任何代码库,即不能调用其任何函数,它只是结构化的数据类型。而且,如果将同一对象编组,那么它将具有其代码库以及结构,并且可以调用其功能?
2014年

18

封送处理是指将函数的签名和参数转换为单字节数组。 专门用于RPC的目的。

序列化通常是指将整个对象/对象树转换为字节数组, 封送处理将序列化对象参数,以便将其添加到消息中并通过网络传递。 *序列化还可以用于存储到磁盘。


11

编组是告诉编译器如何在另一个环境/系统上表示数据的规则;例如;

[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;

如您所见,两个不同的字符串值表示为不同的值类型。

序列化将仅转换对象内容,而不转换表示形式(保持不变),并遵守序列化规则(导出内容或不导出内容)。例如,私有值将不会序列化,公共值是,并且对象结构将保持不变。


7

这是两者的更具体的示例:

序列化示例:

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

typedef struct {
    char value[11];
} SerializedInt32;

SerializedInt32 SerializeInt32(int32_t x) 
{
    SerializedInt32 result;

    itoa(x, result.value, 10);

    return result;
}

int32_t DeserializeInt32(SerializedInt32 x) 
{
    int32_t result;

    result = atoi(x.value);

    return result;
}

int main(int argc, char **argv)
{    
    int x;   
    SerializedInt32 data;
    int32_t result;

    x = -268435455;

    data = SerializeInt32(x);
    result = DeserializeInt32(data);

    printf("x = %s.\n", data.value);

    return result;
}

在序列化中,数据以某种方式被展平,可以在以后存储和取消展平。

编组演示:

(MarshalDemoLib.cpp)

#include <iostream>
#include <string>

extern "C"
__declspec(dllexport)
void *StdCoutStdString(void *s)
{
    std::string *str = (std::string *)s;
    std::cout << *str;
}

extern "C"
__declspec(dllexport)
void *MarshalCStringToStdString(char *s)
{
    std::string *str(new std::string(s));

    std::cout << "string was successfully constructed.\n";

    return str;
}

extern "C"
__declspec(dllexport)
void DestroyStdString(void *s)
{
    std::string *str((std::string *)s);
    delete str;

    std::cout << "string was successfully destroyed.\n";
}

(MarshalDemo.c)

#include <Windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>

int main(int argc, char **argv)
{
    void *myStdString;

    LoadLibrary("MarshalDemoLib");

    myStdString = ((void *(*)(char *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "MarshalCStringToStdString"
    ))("Hello, World!\n");

    ((void (*)(void *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "StdCoutStdString"
    ))(myStdString);

    ((void (*)(void *))GetProcAddress (
        GetModuleHandleA("MarshalDemoLib"),
        "DestroyStdString"
    ))(myStdString);    
}

在封送处理中,数据不必一定要展平,但需要将其转换为其他替代表示形式。所有铸件都是封送,但并非所有封送都是铸件。

封送处理不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但函数希望该对的第一个和第二个元素处于相反的位置;例如,您将一对配对强制转换/存储将无法完成任务,因为fst和snd会被翻转。

#include <stdio.h>

typedef struct {
    int fst;
    int snd;
} pair1;

typedef struct {
    int snd;
    int fst;
} pair2;

void pair2_dump(pair2 p)
{
    printf("%d %d\n", p.fst, p.snd);
}

pair2 marshal_pair1_to_pair2(pair1 p)
{
    pair2 result;
    result.fst = p.fst;
    result.snd = p.snd;
    return result;
}

pair1 given = {3, 7};

int main(int argc, char **argv)
{    
    pair2_dump(marshal_pair1_to_pair2(given));

    return 0;
}

当您开始处理多种类型的带标记的并集时,封送处理的概念变得尤为重要。例如,您可能很难找到一个JavaScript引擎来为您打印“ c字符串”,但是您可以要求它为您打印一个包装的c字符串。或者,如果您想从Lua或Python运行时中的JavaScript运行时中打印字符串。它们都是琴弦,但通常不经过封送处理就不会相处。

我最近的一个烦恼是JScript数组以“ __ComObject”的形式编组到C#,并且没有使用该对象的文档记录方式。我可以找到它的地址,但是我真的对它一无所知,所以真正弄清楚它的唯一方法就是以任何可能的方式戳一下它,并希望找到关于它的有用信息。因此,使用诸如Scripting.Dictionary之类的友好接口创建新对象,将数据从JScript数组对象复制到其中,然后将该对象传递给C#而不是JScript的默认数组,变得更加容易。

test.js:

var x = new ActiveXObject("Dmitry.YetAnotherTestObject.YetAnotherTestObject");

x.send([1, 2, 3, 4]);

yetAnotherTestObject.cs

using System;
using System.Runtime.InteropServices;

namespace Dmitry.YetAnotherTestObject
{
    [Guid("C612BD9B-74E0-4176-AAB8-C53EB24C2B29"), ComVisible(true)]
    public class YetAnotherTestObject
    {
        public void send(object x)
        {
            System.Console.WriteLine(x.GetType().Name);
        }
    }
}

上面打印的是“ __ComObject”,从C#的角度来看,它有点像一个黑匣子。

另一个有趣的概念是,您可能了解如何编写代码,以及一台知道如何执行指令的计算机,因此,作为程序员,您正在有效地编排您希望计算机从大脑到程序执行的概念。图片。如果我们有足够好的编组员,我们可以考虑一下我们想做/更改的事情,程序将以这种方式更改而无需在键盘上键入。因此,如果您有办法在真正想写分号的地方存储大脑中所有物理变化几秒钟,则可以将该数据编组为信号以打印分号,但这是一个极端。


4

编组通常是在相对紧密相关的流程之间进行的;序列化不一定具有这种期望。因此,例如,在流程之间编组数据时,您可能希望仅向可能昂贵的数据发送参考以进行恢复,而对于序列化,则希望保存所有内容,以便在反序列化时正确地重新创建对象。


4

我对编组的理解与其他答案不同。

序列化:

使用约定生成或重新水化对象图的线格式版本。

编组:

通过使用映射文件来生成或再水化对象图的线格式版本,以便可以自定义结果。该工具可以从遵守约定开始,但是重要的区别是自定义结果的能力。

合同优先开发:

编组在合同优先开发的背景下很重要。

  • 可以更改内部对象图,同时保持外部接口随时间稳定。这样,所有的服务订阅者都不必为每次琐碎的更改而进行修改。
  • 可以跨不同语言映射结果。例如,从一种语言(“ property_name”)的属性名称约定到另一种语言(“ propertyName”)的约定。

1
//,我可以进一步了解@JasperBlues在这里的答案是“补水”是什么意思吗?我猜这不只是宇航员的食物。
内森·巴桑尼斯

-根据此答案@NathanBasanese stackoverflow.com/a/6991192/5101816 - (重新)水合的定义包含在下面的话:Hydrating an object is taking an object that exists in memory, that doesn't yet contain any domain data ("real" data), and then populating it with domain data (such as from a database, from the network, or from a file system).
pxsx

3

基础第一

字节流 -流是数据序列。输入流-从源读取数据。输出流-将数据写入目标。Java字节流用于逐字节执行输入/输出(一次8位)。字节流适用于处理原始数据,例如二进制文件。Java字符流用于一次执行2个字节的输入/输出,因为字符是使用Java中的Unicode约定存储的,每个字符2个字节。当我们处理(读/写)文本文件时,字符流很有用。

RMI(远程方法调用) -一种API,提供了一种在Java中创建分布式应用程序的机制。RMI允许对象调用在另一个JVM中运行的对象上的方法。


序列化编组松散地作为同义词使用。这里有一些区别。

序列化 -对象的数据成员被写入二进制形式或字节流(然后可以写入文件/内存/数据库等)。一旦将对象数据成员写入二进制形式,就无法保留有关数据类型的信息。

在此处输入图片说明

编组 -将对象序列化(转换为二进制格式的字节流),并附加数据类型+ Codebase,然后将其传递给Remote Object(RMI)。编组会将数据类型转换为预定的命名约定,以便可以相对于初始数据类型进行重构。 在此处输入图片说明

因此,序列化是编组的一部分。

代码库是一种信息,它告诉Object的接收者可以在哪里找到该对象的实现。任何认为它可能曾经将一个对象传递给另一个可能之前从未看过它的程序的程序,都必须设置代码库,以便接收方可以知道从哪里下载代码(如果它在本地没有可用的代码)。接收器将在反序列化对象后从其获取代码库,并从该位置加载代码。(复制自@Nasir答案)

序列化几乎就像对象使用的内存的愚蠢内存转储,而封送处理则存储有关自定义数据类型的信息。

从某种意义上说,序列化通过传递值的方式执行封送处理,因为没有传递数据类型的信息,只有原始形式传递给字节流。

如果流从一个操作系统转到另一个操作系统,并且不同的操作系统具有不同的表示相同数据的方式,则序列化可能会遇到与大端,小端相关的问题。另一方面,编组在OS之间进行迁移非常好,因为结果是更高级别的表示。


1

封送处理实际上使用序列化过程,但是主要区别在于,在序列化中,仅数据成员和对象本身得到序列化,而没有签名,而在封送对象+代码库(其实现)中也将转换为字节。

编组是使用JAXB将Java对象转换为xml对象,以便可以在Web服务中使用的过程。


0

可以将它们视为同义词,它们都具有将生产者发送给消费者的生产者...在最后,实例字段被写入字节流,而另一端则以相同的实例进行反向攻击。

NB-Java RMI还包含对接收方缺少的类的传输的支持...

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.