Pet*_*ter 472 serialization rpc terminology marshalling
我知道,就几种分布式技术(如RPC)而言,使用术语"编组"但不理解它与序列化的区别.它们不是都将对象转换为一系列位吗?
Jef*_*tin 369
编组和序列化在远程过程调用的上下文中是松散的同义词,但在语义上是不同的.
特别是,编组是关于从这里到那里获取参数,而序列化是关于将结构化数据复制到诸如字节流之类的基本形式或从基本形式复制结构化数据.从这个意义上讲,序列化是执行编组的一种方法,通常实现按值传递语义.
对象也可以通过引用进行编组,在这种情况下,"在线上"的数据只是原始对象的位置信息.但是,这样的对象可能仍然适合于序列化.
正如@Bill所提到的,可能还有其他元数据,例如代码库位置甚至是对象实现代码.
小智 184
两者都有一个共同点 - 即序列化对象.序列化用于传输对象或存储它们.但:
因此序列化是编组的一部分.
CodeBase是告诉Object的接收者可以找到该对象的实现的信息.任何认为它可能将对象传递给之前可能没有看到它的另一个程序的程序必须设置代码库,以便接收方可以知道从哪里下载代码,如果它没有本地可用的代码.在对对象进行反序列化时,接收器将从中获取代码库并从该位置加载代码.
Bil*_*ard 92
来自编组(计算机科学)维基百科的文章:
术语"marshal"被认为与Python标准库1中的"serialize"同义,但这些术语在Java相关RFC 2713中不是同义词:
"编组"对象意味着以这样的方式记录其状态和代码库:当编组对象被"解组"时,可以通过自动加载对象的类定义来获得原始对象的副本.您可以封送任何可序列化或远程的对象.编组就像序列化一样,除了编组还记录代码库.编组与序列化的不同之处在于编组处理特殊的远程对象.(RFC 2713)
"序列化"对象意味着将其状态转换为字节流,使得字节流可以转换回对象的副本.
因此,编组还会在字节流中保存对象的代码以及其状态.
Uri*_*Uri 18
我认为主要区别在于编组据说还涉及代码库.换句话说,您将无法将对象编组和解组为另一个类的状态等效实例..
序列化只是意味着您可以存储对象并重新获得等效状态,即使它是另一个类的实例.
话虽如此,它们通常是同义词.
小智 17
封送处理是指将函数的签名和参数转换为单字节数组. 专门用于RPC的目的.
序列化通常是指将整个对象/对象树转换为字节数组 .Marshaling将序列化对象参数,以便将它们添加到消息中并将其传递到网络中. *序列化也可用于存储到磁盘.*
Teo*_*ahi 10
编组是告诉编译器如何在另一个环境/系统上表示数据的规则; 例如;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
public string cFileName;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 14)]
public string cAlternateFileName;
Run Code Online (Sandbox Code Playgroud)
因为您可以看到两个不同的字符串值表示为不同的值类型.
序列化只会转换对象内容,而不是表示(将保持相同)并遵守序列化规则,(导出或不导出).例如,私有值不会被序列化,公共值为yes,对象结构将保持不变.
Om *_*Sao 10
字节流- 流是数据序列。输入流 - 从源读取数据。输出流 - 将数据写入目标。Java 字节流用于逐字节(一次 8 位)执行输入/输出。字节流适用于处理二进制文件等原始数据。Java 字符流用于一次执行 2 个字节的输入/输出,因为字符是使用 Java 中的 Unicode 约定存储的,每个字符有 2 个字节。当我们处理(读/写)文本文件时,字符流很有用。
RMI(Remote Method Invocation) - 一个 API,它提供了一种在 Java 中创建分布式应用程序的机制。RMI 允许对象调用在另一个 JVM 中运行的对象上的方法。
这两个序列化和编组松散地作为同义词使用。这里有一些不同之处。
序列化- 对象的数据成员被写入二进制形式或字节流(然后可以写入文件/内存/数据库等)。一旦对象数据成员被写入二进制形式,就无法保留有关数据类型的信息。
编组- 对象被序列化(二进制格式的字节流),附加数据类型 + 代码库,然后传递远程对象(RMI)。编组会将数据类型转换为预先确定的命名约定,以便可以根据初始数据类型对其进行重构。

所以序列化是编组的一部分。
CodeBase是告诉 Object 的接收者在哪里可以找到这个对象的实现的信息。任何认为它可能会将一个对象传递给另一个以前可能没有见过它的程序的程序都必须设置代码库,以便接收者可以知道从哪里下载代码,如果它没有本地可用的代码。接收器将在反序列化对象后,从中获取代码库并从该位置加载代码。(从@Nasir 回答中复制)
序列化几乎就像是对象使用的内存的愚蠢内存转储,而编组存储有关自定义数据类型的信息。
在某种程度上,序列化通过值传递的实现来执行编组,因为没有传递数据类型的信息,只是将原始形式传递给字节流。
如果流从一个操作系统传输到另一个操作系统,如果不同的操作系统具有不同的表示相同数据的方式,则序列化可能会遇到一些与大端、小端相关的问题。另一方面,编组非常适合在操作系统之间迁移,因为结果是更高级别的表示。
这是两者的更具体的示例:
序列化示例:
#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;
}
Run Code Online (Sandbox Code Playgroud)
在序列化中,数据以某种方式被展平,可以在以后存储和取消展平。
编组演示:
(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";
}
Run Code Online (Sandbox Code Playgroud)
(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);
}
Run Code Online (Sandbox Code Playgroud)
在封送处理中,数据不必一定要展平,但需要将其转换为其他替代表示形式。所有铸件都是封送,但并非所有封送都是铸件。
封送处理不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但该函数希望该对的第一个和第二个元素处于相反的位置;例如,您将一对配对强制转换/存储将无法完成任务,因为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;
}
Run Code Online (Sandbox Code Playgroud)
当您开始处理多种类型的带标记的联合时,封送处理的概念变得尤为重要。例如,您可能很难找到一个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]);
Run Code Online (Sandbox Code Playgroud)
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
上面打印的是“ __ComObject”,从C#的角度来看,它有点像一个黑匣子。
另一个有趣的概念是,您可能了解如何编写代码,以及一台知道如何执行指令的计算机,因此,作为程序员,您正在有效地编排您希望计算机从大脑到程序执行的概念。图片。如果我们有足够好的编组员,我们可以考虑一下我们想做/更改的事情,程序将以这种方式更改而无需在键盘上键入。因此,如果您有办法在真正想写分号的地方存储大脑中所有物理变化几秒钟,则可以将该数据编组为信号以打印分号,但这是一个极端。