分享
 
 
 

Remoting中数据序列化

王朝c#·作者佚名  2006-12-17
窄屏简体版  字體: |||超大  

数据移动,序列化

该文讲述通过网络传输序列化数据的两个类,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" Â

xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC= Â

"http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV= Â

"http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr= Â

"http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle= Â

"http://schemas.xmlsoap.org/soap/encoding/">

<SOAP-ENV:Body>

<a1:SerialEmployee id="ref-1" xmlns:a1= Â

"http://schemas.microsoft.com/clr/assem/SerialEmployee%2C%20Version%3D0.Â

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" Â

xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC= Â

"http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV= Â

"http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr= Â

"http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAP-ENV:encodingStyle= Â

"http://schemas.xmlsoap.org/soap/encoding/">

<SOAP-ENV:Body>

<a1:SerialEmployee id="ref-1" xmlns:a1= Â

"http://schemas.microsoft.com/clr/assem/SerialEmployee%2C%20Version%3D0.Â

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= Â

"http://schemas.microsoft.com/clr/assem/SerialEmployee%2C%20Version%3D0.Â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();

}

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有