c# vs2012 序列化(Serialize)和反序列化(Deserialize)实际应用

c# vs2012 序列化(Serialize)和反序列化(Deserialize)实际应用

c#中序列化和反序列化又称之为串行化,能够使运行的中的数据结构及数据能够长时间保存起来,用以后面的使用。本文也就实际项目来说明。

一.TCP通信

从初步建立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);
}

验证数据函数

/// 
///  验证连接是否合法.
/// 
/// 
/// 
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 channelList;//通道列表
     public string fileid;
     public int isFullDiskPlay;
     public string strIP;
     public string strPort;

     public Param();

     [Serializable]
     public class CHANNEL_INFO
     {
         public List 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中

/// 
/// 从文件中反序列化出所需要的数据
/// 
/// 文件名(完全路径)
/// 全程记录表
/// 
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,而不能定义两个相同的类结构,不然在反序列化中不能匹配,转化出错。

你可能感兴趣的:(c#)