首页 > 开发 > 综合 > 正文

Remoting中数据序列化

2024-07-21 02:25:29
字体:
来源:转载
供稿:网友
该文讲述通过网络传输序列化数据的两个类,binaryformatter和soapformatter类。这些类可以将类的实例转化成字节流通过网络传输到远程系统,也可以转换回原来的数据。

一、 使用序列化类

序列化一个类,并通过网络传输需要三步:

1、将要序列化的类创建成一个library对象。

2、编写一个发送程序来创建要序列化类的实例,并发送。

3、编写一个接收程序从流中读取数据,并重新创建原来的序列化类。

① 编写要序列化的类

每个要通过网络传输数据的类必须在原代码文件里使用[serializable]标签。这表明,类中所有的数据在传输时都将要被序列化。下面展示了如何创建一个可以序列化的类。

using system;
[serializable]
public class serialemployee
{
public int employeeid
public string lastname;
public string firstname;
public int yearsservice;
public double salary;
public serialemployee()
{
employeeid = 0;
lastname = null;
firstname = null;
yearsservice = 0;
salary = 0.0;
}
}
为了使用该类来传输数据,必须现创建一个library文件:

csc /t:library serialemployee.cs

② 编写一个传输程序

创建数据类以后,可以创建一个程序来传输数据。可以使用binaryformatter和soapformatter类来序列化数据。

binaryformatter将数据序列化为二进制流。通常在实际数据中,增加一些信息,例如类名和版本号信息。

也可以使用soapformatter类使用xml格式来传输数据。使用xml的好处就是可以在任何系统和程序间传递数据。

第一必须创建一个流的实例来传递数据。可以是任何类型的流,包括filestream,memorystream,networkstream。然后,可以创建一个序列化类,使用serialize()方法来通过流对象传递数据:

stream str = new filestream( "testfile.bin", filemode.create, fileaccess.readwrite);
iformatter formatter = new binaryformatter();
formatter.serialize(str, data);

iformatter类创建了一个用来序列化的类的实例(binaryformatter或者soapformatter),使用serialize()类来将数据序列化

using system;
using system.io;
using system.runtime.serialization;
using system.runtime.serialization.formatters.soap;
class soaptest
{
public static void main()
{
serialemployee emp1 = new serialemployee();
serialemployee emp2 = new serialemployee();
emp1.employeeid = 1;
emp1.lastname = "blum";
emp1.firstname = "katie jane";
emp1.yearsservice = 12;
emp1.salary = 35000.50;
emp2.employeeid = 2;
emp2.lastname = "blum";
emp2.firstname = "jessica";
emp2.yearsservice = 9;
emp2.salary = 23700.30;
stream str = new filestream("soaptest.xml", filemode.create,
fileaccess.readwrite);
iformatter formatter = new soapformatter();
formatter.serialize(str, emp1);
formatter.serialize(str, emp2);
str.close();
}
}
soapformatter类包含在system.runtime.serialization.formatters.soap命名空间,binaryformatter类包含在system.runtime.serialization.formatters.binary命名空间,iformatter接口包含在system.runtime.serialization命名空间。

编译代码:csc /r:serialemployee.dll soaptest.cs

运行soaptest.exe程序后,可以查看产生的soaptest.xml文件

<soap-env:envelope xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" &acirc;
xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns:soap-enc= &acirc;
"http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap-env= &acirc;
"http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr= &acirc;
"http://schemas.microsoft.com/soap/encoding/clr/1.0" soap-env:encodingstyle= &acirc;
"http://schemas.xmlsoap.org/soap/encoding/">
<soap-env:body>
<a1:serialemployee id="ref-1" xmlns:a1= &acirc;
"http://schemas.microsoft.com/clr/assem/serialemployee%2c%20version%3d0.&acirc;
0.0.0%2c%20culture%3dneutral%2c%20publickeytoken%3dnull">
<employeeid>1</employeeid>
<lastname id="ref-3">blum</lastname>
<firstname id="ref-4">katie jane</firstname>
<yearsservice>12</yearsservice>
<salary>35000.5</salary>
</a1:serialemployee>
</soap-env:body>
</soap-env:envelope>
<soap-env:envelope xmlns:xsi="http://www.w3.org/2001/xmlschema-instance" &acirc;
xmlns:xsd="http://www.w3.org/2001/xmlschema" xmlns:soap-enc= &acirc;
"http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap-env= &acirc;
"http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr= &acirc;
"http://schemas.microsoft.com/soap/encoding/clr/1.0" soap-env:encodingstyle= &acirc;
"http://schemas.xmlsoap.org/soap/encoding/">
<soap-env:body>
<a1:serialemployee id="ref-1" xmlns:a1= &acirc;
"http://schemas.microsoft.com/clr/assem/serialemployee%2c%20version%3d0.&acirc;
0.0.0%2c%20culture%3dneutral%2c%20publickeytoken%3dnull">
<employeeid>2</employeeid>
<lastname id="ref-3">blum</lastname>
<firstname id="ref-4">jessica</firstname>
<yearsservice>9</yearsservice>
<salary>23700.3</salary>
</a1:serialemployee>
</soap-env:body>
</soap-env:envelope>
查看soaptest.xml文件,我们可以发现在序列化类中soap是如何定义每个数据元素。一个值得注意的重要xml数据特点如下:

<a1:serialemployee id="ref-1" xmlns:a1= &acirc;
"http://schemas.microsoft.com/clr/assem/serialemployee%2c%20version%3d0.&acirc;0.0.0.%2c%20culture%3dneutral%2c%20publickeytoken%3dnull">
这里,xml中定义的数据使用了序列化数据类的实际类名。如果接收程序使用了另一个不同的类名,会和从流中读取的xml数据不匹配。类不匹配,读取将会失败。

下面的代码展示了如何序列化数据,将数据传送到远程系统。

using system;
using system.net;
using system.net.sockets;
using system.runtime.serialization;
using system.runtime.serialization.formatters.binary;
class binarydatasender
{
public static void main()
{
serialemployee emp1 = new serialemployee();
serialemployee emp2 = new serialemployee();
emp1.employeeid = 1;
emp1.lastname = "blum";
emp1.firstname = "katie jane";
emp1.yearsservice = 12;
emp1.salary = 35000.50;
emp2.employeeid = 2;
emp2.lastname = "blum";
emp2.firstname = "jessica";
emp2.yearsservice = 9;
emp2.salary = 23700.30;
tcpclient client = new tcpclient("127.0.0.1", 9050);
iformatter formatter = new binaryformatter();
networkstream strm = client.getstream();
formatter.serialize(strm, emp1);
formatter.serialize(strm, emp2);
strm.close();
client.close();
}
}
因为binaryformatter和soapformatter类需要一个stream对象来传递序列化的数据,所以要使用一个tcp socket对象或者一个tcpclient对象来传递数据,不能直接使用udp。

③编写一个接收程序

using system;
using system.net;
using system.net.sockets;
using system.runtime.serialization;
using system.runtime.serialization.formatters.binary;
class binarydatarcvr
{
public static void main()
{
tcplistener server = new tcplistener(9050);
server.start();
tcpclient client = server.accepttcpclient();
networkstream strm = client.getstream();
iformatter formatter = new binaryformatter();
serialemployee emp1 = (serialemployee)formatter.deserialize(strm);
console.writeline("emp1.employeeid = {0}", emp1.employeeid);
console.writeline("emp1.lastname = {0}", emp1.lastname);
console.writeline("emp1.firstname = {0}", emp1.firstname);
console.writeline("emp1.yearsservice = {0}", emp1.yearsservice);
console.writeline("emp1.salary = {0}/n", emp1.salary);
serialemployee emp2 = (serialemployee)formatter.deserialize(strm);
console.writeline("emp2.employeeid = {0}", emp2.employeeid);
console.writeline("emp2.lastname = {0}", emp2.lastname);
console.writeline("emp2.firstname = {0}", emp2.firstname);
console.writeline("emp2.yearsservice = {0}", emp2.yearsservice);
console.writeline("emp2.salary = {0}", emp2.salary);
strm.close();
server.stop();
}
}

二、 程序改进

在前面的程序中有一个假设:发送者的所有数据都被接收者接收。如果数据丢失,调用deserialize()方法会发生错误。一个简单的解决方法是将序列化数据放到memorystream对象中。memorystream对象将所有的序列化数据保存在内存中,可以很容易得到序列化数据的大小。当传递数据时,将数据大小和数据一起传递。

using system;
using system.io;
using system.net;
using system.net.sockets;
using system.runtime.serialization;
using system.runtime.serialization.formatters.soap;
class betterdatasender
{
public void senddata (networkstream strm, serialemployee emp)
{
iformatter formatter = new soapformatter();
memorystream memstrm = new memorystream();
formatter.serialize(memstrm, emp);
byte[] data = memstrm.getbuffer();
int memsize = (int)memstrm.length;
byte[] size = bitconverter.getbytes(memsize);
strm.write(size, 0, 4);
strm.write(data, 0, memsize);
strm.flush();
memstrm.close();
}
public betterdatasender()
{
serialemployee emp1 = new serialemployee();
serialemployee emp2 = new serialemployee();
emp1.employeeid = 1;
emp1.lastname = "blum";
emp1.firstname = "katie jane";
emp1.yearsservice = 12;
emp1.salary = 35000.50;
emp2.employeeid = 2;
emp2.lastname = "blum";
emp2.firstname = "jessica";
emp2.yearsservice = 9;
emp2.salary = 23700.30;
tcpclient client = new tcpclient("127.0.0.1", 9050);
networkstream strm = client.getstream();
senddata(strm, emp1);
senddata(strm, emp2);
strm.close();
client.close();
}
public static void main()
{
betterdatasender bds = new betterdatasender();
}
}
接收数据程序如下:

using system;
using system.io;
using system.net;
using system.net.sockets;
using system.runtime.serialization;
using system.runtime.serialization.formatters.soap;
class betterdatarcvr
{
private serialemployee recvdata (networkstream strm)
{
memorystream memstrm = new memorystream();
byte[] data = new byte[4];
int recv = strm.read(data, 0, 4);
int size = bitconverter.toint32(data, 0);
int offset = 0;
while(size > 0)
{
data = new byte[1024];
recv = strm.read(data, 0, size);
memstrm.write(data, offset, recv);
offset += recv;
size -= recv;
}
iformatter formatter = new soapformatter();
memstrm.position = 0;
serialemployee emp = (serialemployee)formatter.deserialize(memstrm);
memstrm.close();
return emp;
}
public betterdatarcvr()
{
tcplistener server = new tcplistener(9050);
server.start();
tcpclient client = server.accepttcpclient();
networkstream strm = client.getstream();
serialemployee emp1 = recvdata(strm);
console.writeline("emp1.employeeid = {0}", emp1.employeeid);
console.writeline("emp1.lastname = {0}", emp1.lastname);
console.writeline("emp1.firstname = {0}", emp1.firstname);
console.writeline("emp1.yearsservice = {0}", emp1.yearsservice);
console.writeline("emp1.salary = {0}/n", emp1.salary);
serialemployee emp2 = recvdata(strm);
console.writeline("emp2.employeeid = {0}", emp2.employeeid);
console.writeline("emp2.lastname = {0}", emp2.lastname);
console.writeline("emp2.firstname = {0}", emp2.firstname);
console.writeline("emp2.yearsservice = {0}", emp2.yearsservice);
console.writeline("emp2.salary = {0}", emp2.salary);
strm.close();
server.stop();
}
public static void main()
{
betterdatarcvr bdr = new betterdatarcvr();
}
}


收集最实用的网页特效代码!

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表