Socket开发探秘--数据封包和拆包

我们发送数据的时候,内容部分肯定是按照一定协议规则串联起来的数据,那么我们就需要把实体转化为发送的数据格式。综上所述,我们通过实体类,必须实现数据的发送和读取的转换。


/// <summary>
/// 测试数据的实体类信息
/// </summary>
public class TestDataRequest
{
#region MyRegion

/// <summary>
/// 请求序列
/// </summary>
public string seq;
/// <summary>
/// 用户帐号
/// </summary>
public string userid;
/// <summary>
/// 用户密码
/// </summary>
public string psw;

#endregion

public TestDataRequest( string seq, string userid, string psw)
{
this .seq = seq;
this .userid = userid;
this .psw = psw;
}
public TestDataRequest()
{
}

/// <summary>
/// 转换Socket接收到的信息为对象信息
/// </summary>
/// <paramname="data"> Socket接收到的信息 </param>
public TestDataRequest( string data)
{
string []dataArray = null ;
dataArray
= NetStringUtil.UnPack(data);
if (dataArray != null && dataArray.Length > 0 )
{
TestDataRequestnewAnswerData
= new TestDataRequest();
int i = 0 ;
this .seq = dataArray[i ++ ];
this .userid = dataArray[i ++ ];
this .psw = dataArray[i ++ ];
}
}

/// <summary>
/// 转换对象为Socket发送格式的字符串
/// </summary>
/// <returns></returns>
public override string ToString()
{
string data = "" ;
data
= this .seq + " | " + this .userid + " | " + this .psw.ToString();
data
= NetStringUtil.PackSend(DataTypeKey.TestDataRequest,data);
return data;
}

以上把数据的处理放在了实体类中进行封包和拆包,是一种比较好的做法,但是由于数据的封包拆包是一个繁琐的过程,代码重复性比较多,而且也容易出错。

这里设计了一个基类,来改进这种方式的数据处理,我们把所有对数据的拆包和封包,利用反射机制,减少我们的代码量,提高代码的优雅性。


public class BaseEntity
{
protected string HeaderKey;

public BaseEntity()
{
}

/// <summary>
/// 转换Socket接收到的信息为对象信息
/// </summary>
/// <paramname="data"> Socket接收到的信息 </param>
public BaseEntity( string data)
{
string []dataArray = null ;
dataArray
= NetStringUtil.UnPack(data);
if (dataArray != null && dataArray.Length > 0 )
{
int i = 0 ;
FieldInfo[]fieldArray
= ReflectionUtil.GetFields( this );
if (fieldArray == null || dataArray.Length != fieldArray.Length)
{
throw new ArgumentException( " 收到的信息和字段信息不一致 " );
}

if (fieldArray != null )
{
foreach (FieldInfoinfo in fieldArray)
{
string strValue = dataArray[i ++ ];
ReflectionUtil.SetField(
this ,info.Name,strValue);
}
}
}
}

/// <summary>
/// 转换对象为Socket发送格式的字符串
/// </summary>
/// <returns></returns>
public override string ToString()
{
string data = "" ;
FieldInfo[]fieldArray
= ReflectionUtil.GetFields( this );
StringBuildersb
= new StringBuilder();
if (fieldArray != null )
{
foreach (FieldInfoinfo in fieldArray)
{
sb.Append(ReflectionUtil.GetField(
this ,info.Name));
sb.Append(
" | " );
}
}

data
= sb.ToString().Trim( ' | ' );
if ( string .IsNullOrEmpty(HeaderKey))
{
throw new ArgumentNullException( " DataTypeKey " , " 实体类未指定协议类型 " );
}
data
= NetStringUtil.PackSend(HeaderKey,data);
return data;
}
}

以上的是实体类的基类,它封装了数据的拆包和封包过程,只需要在子类代码中指定协议头就可以了。子类的代码如下所示。

下面的代码是收到数据包,利用实体类构造函数,解析为实体类的操作,以及构造实体类,通过ToString()方式把实体类信息转化为可以发送的数据包的操作。


private void TestDataHandle(PreDatadata)
{
TestDataRequestrequest
= new TestDataRequest(data.Content);
Log.WriteInfo(
string .Format( " ############{0} " ,request.ToString()));

TestDataAnswerDataanswerData
= new TestDataAnswerData(request.Seq,request.UserId,request.Password);
ShopClientManager.This.AddSend(data.UserId,answerData.ToString(),
true );
}

我编写的测试例子中,实体类的继承图如下所示。

Socket开发探秘--数据封包和拆包_第1张图片

你可能感兴趣的:(socket)