c#中序列化和反序列化又稱之為串行化,能夠使運行的中的數據結構及數據能夠長時間保存起來,用以后面的使用。本文也就實際項目來說明。
從初步建立TCP連接,到發送驗證數據包數據,這邊就需要向服務器發送數據。發送的數據是驗證信息,就簡單來說,如果是一個字符串,這里面我們用TCP可以直接寫入流就行了:
//客戶端 string content = "發送的數據"; Byte[] bytSend = Encoding.UTF8.GetBytes(content); ntwStream.Write(bytSend, 0, bytSend.Length);而相對應的服務器接收數據應該是這樣:
//服務器listener.Listen(0); Socket socket = listener.Accept(); NetworkStream ntwStream = new NetworkStream(socket); StreamReader strmReader = new StreamReader(ntwStream); strmReader.ReadToEnd()這種傳輸數據結構相對很簡單的TCP可以直接傳輸即可,但是對于相對復雜的結構的數據,類的實例,需要的數據有int,string,還有文件列表List<>等等,那么簡單數據傳輸就不適用了(也可以簡單傳輸,但是解析相對困難),這時候就需要序列化(后面有復雜結構示例),下面就以驗證數據包來說明,數據包包括登錄名和密碼
//在要序列化的類上面加上[Serializable]聲明這個類是可以序列化的[Serializable]public class LoginInfo{//登入數據包. public String strUID = null;//用戶名 public String strPWD = null;//密碼. public Int32 iState = 0;//狀態值. }客戶端發送驗證數據包
//客戶端System.Runtime.Serialization.Formatters.Binary.BinaryFormatter mBinaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();try{ //連接服務器 ClientTcp.Connect(System.Net.ipAddress.Parse(strIPAddr),iPort); //發送驗證數據包 LoginInfo mLoginInfo = new LoginInfo(); mLoginInfo.strPWD = "passWord"; mLoginInfo.strUID = "administrator"; mLoginInfo.iState = bIsShowListMsg ? 100 : 0; mBinaryFormatter.Serialize(ClientTcp.GetStream(), mLoginInfo); object oNetData = mBinaryFormatter.Deserialize(ClientTcp.GetStream()); ReturnInfoValue mReturnValue = oNetData as ReturnInfoValue; if (mReturnValue == null) return null; if (mReturnValue.iReturnValue == VideoStreamCommon.NetPacket.RIV_ERROE) return null; return ClientTcp; } catch (System.Exception error) { MessageBox.Show("創建TCP發生異常,異常信息:" + error.Message); }服務器接收驗證包
try{ listenerTcp.Start(); do { TcpClient mClientTcp = listenerTcp.AcceptTcpClient(); if (mClientTcp == null) break; oNetData = mBinaryFormatter.Deserialize(mThreadParam.ClientTcp.GetStream()); if (bIsCheckClient == false) {//先驗證數據. int iTepValue = CheckClientInfo(oNetData); if (iTepValue == 2) {//創建消息窗口. AsyncSetWorkThreadParam(ref mThreadParam, 1001, true);//添加線消息窗口列表. } bIsCheckClient = (iTepValue != 0); if (bIsCheckClient) continue;//驗證數據成功. else break; //驗證數據失敗. } } while (true);}catch (System.Exception ep){//系統異常. ep.Message.ToString(); AsyncAddListMessage("端口被占用:" + strIPAddr, 0);}驗證數據函數
/// <summary>/// 驗證連接是否合法./// </summary>/// <param name="param"></param>/// <returns></returns>public int CheckClientInfo(object param){ LoginInfo mLoginInfo = param as LoginInfo; if (mLoginInfo == null) return 0; if(mLoginInfo.strUID == "administrator" && mLoginInfo.strPWD == "password") { return 1; } else { return 0; }}當程序功能化之后,每個人負責不同模塊,這就會涉及到創建一個進程,然后向該進程傳遞必要的參數,如果參數中數據結構比較復雜也得使用序列化,調用進程序列化文件后,被調用進程再解析該文件,實現數據傳遞。下面上代碼:
[Serializable] public class Param { public List<Param.CHANNEL_INFO> channelList;//通道列表 public string fileid; public int isFullDiskPlay; public string strIP; public string strPort; public Param(); [Serializable] public class CHANNEL_INFO { public List<Param.FILE_INFO> fileList; public int id; public string name; public CHANNEL_INFO(); } [Serializable] public class FILE_INFO { public DateTime dtBegin; public DateTime dtEnd; public string name; public FILE_INFO(); } public bool SeveToFile(string strFileName) { try { IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(strFileName, FileMode.Create, Fileaccess.Write, FileShare.None); formatter.Serialize(stream, this); stream.Close(); return true; } catch (System.Exception ex) { return false; } } public static Param LoadFromFile(string strFileName) { try { IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read); VideoStreamParam_Hik video = formatter.Deserialize(stream) as VideoStreamParam_Hik; stream.Close(); return video; } catch (System.Exception ex) { return null; } } }下面是調用部分
//序列化文件名稱(GUID名稱)strFileName = Guid.NewGuid().ToString() + ".bin";//保存到bin文件if (!videomodel.SeveToFile(strFileName)){ MessageBox.Show("測試失敗"); return;}//開啟一個進程System.Diagnostics.PRocess PlayStream = new System.Diagnostics.Process();PlayStream.StartInfo.UseShellExecute = false;PlayStream.StartInfo.Arguments = strFileName;PlayStream.StartInfo.CreateNoWindow = true;PlayStream.StartInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "test.exe";PlayStream.Start();最后是調用解析部分,該部分再test.exe中
/// <summary>/// 從文件中反序列化出所需要的數據/// </summary>/// <param name="strFileName">文件名(完全路徑)</param>/// <param name="qcjl_displayTable">全程記錄表</param>/// <returns></returns>public bool LoadFromFile(string strFileName, ref Param param){ try { IFormatter formatter = new BinaryFormatter(); Stream stream = new FileStream(strFileName, FileMode.Open, FileAccess.Read, FileShare.Read); param = new Param(); param = (Param)formatter.Deserialize(stream); stream.Close(); return true; } catch (System.Exception ex) { MessageBox.Show("反序列化發生異常!,異常信息:" + ex.Message); return false; }}上面反序列化的實例和傳遞的部分是一樣的,這樣就可以使用其中的參數了。 最后還要說明一下,序列化和反序列化的的類應該使用公用的類,即定義一個兩個程序公用的類,都調用該公共的dll,而不能定義兩個相同的類結構,不然在反序列化中不能匹配,轉化出錯。
新聞熱點
疑難解答