在前面講述的篇幅中,發送的都是文本信息,我們只要通過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進行序列化。在 這裡還有一個細節值得一提,那就是消息邊界問題的處理,這裡是利用發送消息 的長度方法來實現。代碼如下:
1int memsize = (int) mem.Length;
通過 BitConverter.GetBytes()方法可以把數據類型轉化為二進制數組,從而可以在 網絡上傳送,所以在接收的時候先接收消息長度,再通過該長度來循環讀取完整 的消息。
2 byte[] size = BitConverter.GetBytes (memsize);
3 ns.Write(size, 0, 4);
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序列化,兼容性高,可以兼容不同系統之間的通信, 而二進制不行。可以說各有利弊,可以根據實際情況來選擇哪一種序列化。
該篇暫時就寫到這裡了,文字有點亂,請見諒。
本文配套源碼