转载至:http://www.cnblogs.com/licongjie/archive/2006/10/27/542024.html
Socket网络编程学习笔记(5):发送和接收实体类数据
在前面讲述的篇幅中,发送的都是文本信息,我们只要通过Encoding中的几个方法把文本转化成二进制数组就可以利用Socket来传输了,这对于一些基本的信息传输能够得到满足,但对于一些复杂的消息交流,则有些“吃力”。我们有时候会把一些信息封闭在一个类中,如果Socket能够传送类对象,那么一些复杂的问题能够通过面向对象来解决了,即方便又安全。大家都知道,要想在网络上传输信息,必须要经过序列化才行,所以在传送类对象时,首选必须对该类对象进行序列化,才能够在网络上进行传输。
序列化类对象有三种序列化方法:
1、Xml序列化
2、Binary序列化
3、Soap序列化
这几种序列化方法,运用方法相类似,只不过用到的类不一样。在这里也不一一讲述了,有兴趣的朋友可以到网上搜一搜,相信会有不少的收获。这里主要讲一下利用Soap序列化来传送消息。
1、首先我们先来建立一个实体类,用来做消息的载体
1using System; 2using System.Collections.Generic; 3using System.Text; 4 5namespace sbwConsole 6{ 7 [Serializable] 8 public class SocketData 9 { 10 private OperateType _operateType; 11 private OperateInfo _operateInfo; 12 private string _connString; 13 private string _clientIP; 14 private string _serverIP; 15 16 /// <summary> 17 /// 指令传输数据 18 /// </summary> 19 /// <param name="operateType">指令类型</param> 20 /// <param name="operateInfo">指令信息</param> 21 /// <param name="connString">ASP数据库连接字符串</param> 22 /// <param name="clientIP">子服务器IP</param> 23 /// <param name="serverIP">ASP服务器IP</param> 24 public SocketData(OperateType operateType, OperateInfo operateInfo, 25 string connString, string clientIP, string serverIP) 26 { 27 _operateType = operateType; 28 _operateInfo = operateInfo; 29 _connString = connString; 30 _clientIP = clientIP; 31 _serverIP = serverIP; 32 } 33 34 /// <summary> 35 /// 指令类型 36 /// </summary> 37 public OperateType OperateType 38 { 39 get { return _operateType; } 40 set { _operateType = value; } 41 } 42 /// <summary> 43 /// 指令信息 44 /// </summary> 45 public OperateInfo OperateInfo 46 { 47 get { return _operateInfo; } 48 set { _operateInfo = value; } 49 } 50 /// <summary> 51 /// ASP数据库连接字符串 52 /// </summary> 53 public string ConnString 54 { 55 get { return _connString; } 56 set { _connString = value; } 57 } 58 /// <summary> 59 /// 子服务器IP 60 /// </summary> 61 public string ClientIP 62 { 63 get { return _clientIP; } 64 set { _clientIP = value; } 65 } 66 /// <summary> 67 /// ASP服务器IP 68 /// </summary> 69 public string ServerIP 70 { 71 get { return _serverIP; } 72 set { _serverIP = value; } 73 } 74 } 75 76 /// <summary> 77 /// 指令类型 78 /// </summary> 79 public enum OperateType 80 { 81 /// <summary> 82 /// 网站操作 83 /// </summary> 84 Web = 0, 85 /// <summary> 86 /// 升级 87 /// </summary> 88 Upgrade, 89 /// <summary> 90 /// 迁移 91 /// </summary> 92 Transfer 93 } 94 95 /// <summary> 96 /// 指令信息 97 /// </summary> 98 public enum OperateInfo 99 { 100 /// <summary> 101 /// 发送 102 /// </summary> 103 Send = 0, 104 /// <summary> 105 /// 出错 106 /// </summary> 107 Error, 108 /// <summary> 109 /// 成功 110 /// </summary> 111 Success, 112 /// <summary> 113 /// 重发 114 /// </summary> 115 SendAgain 116 } 117} 118
2、发送前先把类对象进行Soap序列化
1public static void Send(NetworkStream ns, SocketData sd) 2 { 3 IFormatter formatter = new SoapFormatter(); 4 MemoryStream mem = new MemoryStream(); 5 6 formatter.Serialize(mem, sd); 7 byte[] data = mem.GetBuffer(); 8 int memsize = (int)mem.Length; 9 byte[] size = BitConverter.GetBytes(memsize); 10 ns.Write(size, 0, 4); 11 ns.Write(data, 0, memsize); 12 ns.Flush(); 13 mem.Close(); 14 }
这里利用 IFormatter formatter = new SoapFormatter(); MemoryStream mem = new MemoryStream();
formatter.Serialize(mem, sd); 对类对象sd进行序列化。在这里还有一个细节值得一提,那就是消息边界问题的处理,这里是利用发送消息的长度方法来实现。代码如下:
1
int memsize = (
int)mem.Length;
2
byte[] size = BitConverter.GetBytes(memsize);
3
ns.Write(size, 0, 4);
通过BitConverter.GetBytes()方法可以把数据类型转化为二进制数组,从而可以在网络上传送,所以在接收的时候先接收消息长度,再通过该长度来循环读取完整的消息。
3、接收消息
1public static SocketData Receive(NetworkStream ns) 2 { 3 MemoryStream mem = new MemoryStream(); 4 SocketData sd; 5 byte[] data = new byte[4]; 6 int revc = ns.Read(data, 0, 4); 7 int size = BitConverter.ToInt32(data, 0); 8 int offset = 0; 9 10 if (size > 0) 11 { 12 while (size > 0) 13 { 14 data = new byte[1024]; 15 revc = ns.Read(data, offset, size); 16 mem.Write(data, offset, revc); 17 offset += revc; 18 size -= revc; 19 } 20 21 IFormatter formatter = new SoapFormatter(); 22 mem.Position = 0; 23 sd = (SocketData)formatter.Deserialize(mem); 24 mem.Close(); 25 } 26 else 27 { 28 sd = null; 29 } 30 return sd; 31 }
通过sd = (SocketData)formatter.Deserialize(mem);还原数据为类对象,就可以对此类对象进行访问了。用Xml序列化或用二进制序列化也是类似,只不过把序列化的方法改一下就可以了,一般来说用二进制序列化得到的数据最小,占用带宽也最小,而用xml和Soap来序列化,都是序列化为Xml格式,所以数据比较大,占用带宽比较大。但用xml或Soap序列化,兼容性高,可以兼容不同系统之间的通信,而二进制不行。可以说各有利弊,可以根据实际情况来选择哪一种序列化。