序列化和封送有什么区别?
我知道,就几种分布式技术(如RPC)而言,使用术语“封送”,但不明白它与序列化的区别。 他们是不是都把物体变成一连串的碎片?
有关:
什么是序列化?
什么是对象编组?
在远程过程调用的背景下,封送和序列化是松散的同义词,但在语义上与意图不同。
特别地,编组是指从这里到那里获取参数,而序列化则是将结构化数据复制到诸如字节stream之类的原始forms。 从这个意义上讲,序列化是执行封送处理的一种手段,通常实现按值传递语义。
对象也可以通过引用编组,在这种情况下,“在线上”的数据只是原始对象的位置信息。 然而,这样的对象可能仍然是值得序列化的。
正如@Bill提到的那样,可能会有额外的元数据,比如代码库位置,甚至对象实现代码。
两者都有一个共同点 – 就是序列化一个对象。 序列化用于传输对象或存储它们。 但:
- 序列化:当序列化一个对象时,只有该对象中的成员数据被写入字节stream; 而不是实际实现该对象的代码。
- 编组:术语编组是在将对象传递给远程对象(RMI)时使用的 。 在编组对象被序列化(成员数据被串行化) +附加代码库。
所以序列化是编组的一部分。
CodeBase是告诉Object的接收者可以find这个对象的实现的信息。 任何认为它可能将对象传递给其他程序的程序,如果它没有本地可用的代码,则必须设置代码库,以便接收者可以知道从哪里下载代码。 接收器在反序列化对象时,将从中取出代码库并从该位置加载代码。
从编组(计算机科学)维基百科文章:
术语“元帅”被认为与Python标准库1中的“序列化”同义,但是这些术语在Java相关的RFC 2713中不是同义的:
“编组”对象意味着以这样的方式logging它的状态和代码库,当编组对象被“解组”时,可能通过自动加载对象的类定义来获得原始对象的副本。 您可以编组任何可序列化或远程的对象。 编组就像序列化,除了编组也logging代码库。 编组不同于序列化,因为编组对待特定的远程对象。 (RFC 2713)
要“序列化”一个对象意味着将其状态转换为字节stream,以便字节stream可以被转换回对象的副本。
因此,除了状态之外,编组还会将字节stream中对象的代码保存起来。
我认为主要的区别在于,编组也应该涉及代码库。 换句话说,你将不能把一个对象编组和解组成一个不同类的状态等价实例。 。
序列化只是意味着你可以存储对象并重新获得一个等价的状态,即使它是另一个类的一个实例。
这就是说,他们通常是同义词。
封送是指将函数的签名和参数转换为单个字节数组。 特别是为了RPC的目的。
序列化通常是指将整个对象/对象树转换为一个字节数组。 封送将序列化对象参数,以便将它们添加到消息中并通过networking传递。 *序列化也可用于存储到磁盘。*
编组是指示编译器如何在另一个环境/系统上表示数据的规则; 例如;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)] public string cFileName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)] public string cAlternateFileName;
你可以看到两个不同的string值表示为不同的值types。
序列化只会转换对象内容,而不是表示(将保持不变),并遵守序列化规则(导出或不导出)。 例如,私有值不会被序列化,公有值是和对象结构将保持相同。
编组通常在相对密切的过程之间进行; 系列化不一定有这样的期望。 因此,在进程之间编组数据时,例如,您可能希望只发送一个REFERENCE到可能需要昂贵的数据才能恢复,而使用序列化时,则希望将其全部保存,以便在反序列化时正确地重新创build对象。
我对编组的理解与其他答案不同。
连载:
使用约定来生成或重新组织一个对象图的线格式版本。
编组:
通过利用映射文件生成或补充对象图的线格式版本,以便可以自定义结果。 该工具可能会遵循惯例开始,但重要的不同是定制结果的能力。
合同首先发展:
在合同第一次发展的背景下,编组是非常重要的。
- 可以对内部对象图进行更改,同时保持外部接口在一段时间内保持稳定。 这样,所有的服务用户都不必为每一个小小的变化而修改。
- 可以将结果映射到不同的语言。 例如从一种语言('property_name')的属性名称约定到另一种语言('propertyName')。
把它们看作是同义词,都有一个生产者把东西发送给消费者…最后,实例的字段被写入字节stream,另一端则反过来,并且具有相同的实例。
注意 – Java RMI还包含传输从收件人丢失的类的支持…
以下是两个更具体的例子:
序列化示例:
#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); }
在编组过程中,数据不一定需要变平,但需要转换成另一种替代表示。 所有的铸造都是编组,而不是所有的编组都在铸造。
编组不需要dynamic分配涉及,也可以只是结构之间的转换。 例如,你可能有一对,但function期望对的第一个和第二个元素是相反的; 你将一对/ memcpy转换成另一个不会做这个工作,因为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; }
当您开始处理多种types的标记联合时,编组的概念变得尤为重要。 例如,您可能会发现很难让JavaScript引擎为您打印“cstring”,但您可以要求它为您打印一个包装的cstring。 或者,如果您想在Lua或Python运行库中从JavaScript运行时打印string。 他们都是弦乐,但是如果没有编组,他们往往不会相处。
我最近烦恼的是,JScript数组编组为C#的“__ComObject”,并没有logging的方式来玩这个对象。 我可以find它所在的地址,但是我真的不知道有什么关于它的地方,所以唯一真正想到的办法是以任何可能的方式来捅它,并希望find有用的信息。 因此,使用像Scripting.Dictionary这样的友好界面创build一个新对象变得更容易,将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#的angular度来看,这是一个黑盒子。
另一个有趣的概念是,你可能会理解如何编写代码,以及知道如何执行指令的计算机,所以作为一名程序员,你正在有效地编排计算机从你的大脑到程序的想法图片。 如果我们有足够好的marshailer,我们可以想到我们想要做什么/改变,程序会改变这种方式,而无需键盘上的input。 所以,如果你可以有一种方法来存储你脑中的所有物理变化几秒钟,你真的想写一个分号,你可以把这些数据编组成一个信号打印分号,但这是一个极端的。
Marshaling实际上使用Serialization过程,但主要区别在于它在Serialization中只有数据成员和对象本身被序列化而不是签名,但是在Marshalling Object +代码库(它的实现)也会被转换成字节。
编组是将java对象转换为使用JAXB的xml对象的过程,以便它可以在Web服务中使用。