我知道在一些分布式技术(如RPC)中,使用了术语“封送”,但不理解它与序列化有何不同。它们不是都在把对象转换成一系列的比特吗?
相关:
什么是序列化?
什么是对象编组?
我知道在一些分布式技术(如RPC)中,使用了术语“封送”,但不理解它与序列化有何不同。它们不是都在把对象转换成一系列的比特吗?
相关:
什么是序列化?
什么是对象编组?
当前回答
序列化vs编组
问题:对象属于某个进程(VM),其生命周期是相同的
序列化-将对象状态转换为字节流(JSON, XML…)用于保存,共享,转换…
编组-包含序列化+代码库。它通常用于远程过程调用(RPC) -> Java远程方法调用(Java RMI),在这里您可以调用托管在远程Java进程上的对象的方法。
codebase -是类定义的一个地方或URL,它可以被ClassLoader下载。CLASSPATH[About]作为一个本地代码库
JVM -> Class Loader -> load class definition
java -Djava.rmi.server.codebase="<some_URL>" -jar <some.jar>
非常简单的RMI图
Serialisation - state
Marshalling - state + class definition
官方文档
其他回答
可以把它们看作同义词,它们都有一个生产者,把东西发送给消费者……在实例的结束字段被写入一个字节流,而另一端则将相同的实例反向和向上写入。
注意: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);
}
在封送处理中,数据不一定需要被平铺,但需要转换为另一种替代表示。所有类型转换都是编组,但并不是所有编组都是类型转换。
封送处理不需要涉及动态分配,它也可以只是结构之间的转换。例如,您可能有一对,但函数期望对的第一个和第二个元素是相反的;你把一对施放/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;
}
当您开始处理多种类型的带标签联合时,封送的概念变得尤为重要。例如,您可能会发现很难让JavaScript引擎为您打印一个“c字符串”,但您可以要求它为您打印一个包装好的c字符串。或者如果你想在Lua或Python运行时从JavaScript运行时打印字符串。它们都是字符串,但如果没有编组,通常就无法处理。
An annoyance I had recently was that JScript arrays marshal to C# as "__ComObject", and has no documented way to play with this object. I can find the address of where it is, but I really don't know anything else about it, so the only way to really figure it out is to poke at it in any way possible and hopefully find useful information about it. So it becomes easier to create a new object with a friendlier interface like Scripting.Dictionary, copy the data from the JScript array object into it, and pass that object to C# instead of JScript's default array.
(. 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#的角度来看,这有点像一个黑盒。
Another interesting concept is that you might have the understanding how to write code, and a computer that knows how to execute instructions, so as a programmer, you are effectively marshaling the concept of what you want the computer to do from your brain to the program image. If we had good enough marshallers, we could just think of what we want to do/change, and the program would change that way without typing on the keyboard. So, if you could have a way to store all the physical changes in your brain for the few seconds where you really want to write a semicolon, you could marshal that data into a signal to print a semicolon, but that's an extreme.
在远程过程调用的上下文中,封送处理和序列化大体上是同义的,但在语义上就意图而言是不同的。
特别地,封送处理是关于从这里到那里获取参数,而序列化是关于将结构化数据复制到字节流等基本形式或从中复制。在这个意义上,序列化是执行封送处理的一种方法,通常实现值传递语义。
也可以通过引用封送对象,在这种情况下,“在线上”的数据只是原始对象的位置信息。但是,这样的对象仍然可以接受值序列化。
正如@Bill提到的,可能会有额外的元数据,比如代码基位置,甚至是对象实现代码。
封送处理是指将函数的签名和参数转换为单字节数组。 专门用于RPC的目的。
序列化通常是指将整个对象/对象树转换为字节数组 封送处理将序列化对象参数,以便将它们添加到消息中并通过网络传递。 序列化也可以用于存储到磁盘
编组通常在相对紧密关联的进程之间进行;序列化不一定有这种期望。因此,当在进程之间编组数据时,例如,您可能希望仅发送一个引用到可能昂贵的数据以进行恢复,而使用序列化时,您可能希望保存所有数据,以便在反序列化时正确地重新创建对象。