Remoting中資料序列化

來源:互聯網
上載者:User
資料 該文講述通過網路傳輸序列化資料的兩個類,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();
}
}


相關文章

E-Commerce Solutions

Leverage the same tools powering the Alibaba Ecosystem

Learn more >

Apsara Conference 2019

The Rise of Data Intelligence, September 25th - 27th, Hangzhou, China

Learn more >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。