
该文讲述通过网络传输序列化数据的两个类,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文档
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/">
"http://schemas.microsoft.com/clr/assem/serialemployee%2c%20version%3d0.â
0.0.0%2c%20culture%3dneutral%2c%20publickeytoken%3dnull">
1
blum
katie jane
12
35000.5
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/">
"http://schemas.microsoft.com/clr/assem/serialemployee%2c%20version%3d0.â
0.0.0%2c%20culture%3dneutral%2c%20publickeytoken%3dnull">
2
blum
jessica
9
23700.3
查看soaptest.xml文档,我们能够发现在序列化类中soap是怎样定义每个数据元素。一个值得注意的重要xml数据特点如下:
"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();
}
}
|