前面发表过两篇随笔:《
Socket开发探秘--基类及公共类的定义
》和《
Socket开发探秘--数据封包和拆包
》,介绍了Socket方面的开发。本文继续探讨使用Json格式来作为Socket收发协议方面的技术问题。

前面说到,
收到的Socket数据经过粗略的解析后,就是PreData类型的数据,这个是通用的数据格式,我们需要进一步处理才能转化为所能认识的数据对象(实体类对象),同样,我们发送数据的时候,内容部分肯定是按照一定协议规则串联起来的数据,那么我们就需要把实体转化为发送的数据格式。综上所述,我们通过实体类,必须实现数据的发送和读取的转换。

由于数据的封包拆包是一个繁琐的过程,代码重复性比较多,而且也容易出错。前面介绍过
设计一个基类,我们把所有对数据的拆包和封包,利用反射机制,减少我们的代码量,提高代码的优雅性。
但是后来有人建议,可能使用Json格式的数据内容可能更好,确实,如果是采用以|分割符号的内容,有一个缺点,就是数据内容比较难懂(有时候我们还是需要分析数据包的),Json会更易读一些。
另外,使用Json可以脱离字段顺序的关系,可以向后兼容一些历史的协议,例如首次定义的协议有字段A、B,后来服务器升级,升级增加支持C、D,旧的客户端可以和新的客户端并存,增加了兼容性。
因此我在此基础上优化一下代码,使其支持Json格式的数据发送,其实由于之前的代码封装的还算比较好,因此修改为Json格式的协议内容,只需要修改BaseEntity中几行代码即可实现,下面贴出修改代码的前后对比(注释掉的代码是原来的代码):




代码


public

class
BaseEntity
{

protected

string
HeaderKey;


public
BaseEntity()
{
}


///

<summary>


///
转换Socket接收到的信息为对象信息

///

</summary>


///

<param name="data">
Socket接收到的信息
</param>



public
BaseEntity(
string
data)
{

#region
普通按顺序构造的代码


//
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 (FieldInfo info in fieldArray)

//
{

//
string strValue = dataArray[i++];

//
ReflectionUtil.SetField(this, info.Name, strValue);

//
}

//
}

//
}



#endregion



//
Json格式转换后的内容,肯定是小于或者等于实体类的内容

//
因为对象要兼容历史的Json内容,通过反射以最小的成员来赋值


BaseEntity obj
=
JsonTools.JsonToObject(data,
this
.GetType())
as
BaseEntity;

if
(obj
!=

null
)
{
FieldInfo[] fieldArray

=
ReflectionUtil.GetFields(obj);

foreach
(FieldInfo info
in
fieldArray)
{

object
value
=
ReflectionUtil.GetField(obj, info.Name);
ReflectionUtil.SetField(

this
, info.Name, value);
}
}
}


///

<summary>


///
转换对象为Socket发送格式的字符串

///

</summary>


///

<returns></returns>



public

override

string
ToString()
{

string
data
=

""
;


#region
普通按顺序构造的代码


//
FieldInfo[] fieldArray = ReflectionUtil.GetFields(this);

//
StringBuilder sb = new StringBuilder();

//
if (fieldArray != null)

//
{

//
foreach (FieldInfo info in fieldArray)

//
{

//
sb.Append(ReflectionUtil.GetField(this, info.Name));

//
sb.Append("|");

//
}

//
}

//
data = sb.ToString().Trim('|');



#endregion



#region
按Json格式构造的代码


data

=
JsonTools.ObjectToJson(
this
);


#endregion




if
(
string
.IsNullOrEmpty(HeaderKey))
{

throw

new
ArgumentNullException(
"
DataTypeKey
"
,
"
实体类未指定协议类型
"
);
}
data

=
NetStringUtil.PackSend(HeaderKey, data);

return
data;
}
}

JsonTools是一个Json的辅助类,负责Json内容的解析的,由于我的项目是采用C#2.0的,因此Json操作采用了Newtonsoft.Json.dll类库,如果是C#3.5的,采用系统内置类库就可以了。




代码


///

<summary>


///
Json处理类

///

</summary>



public

class
JsonTools
{

///

<summary>


///
从一个对象信息生成Json串

///

</summary>


///

<param name="obj"></param>


///

<returns></returns>



public

static

string
ObjectToJson(
object
obj)
{

return
JavaScriptConvert.SerializeObject(obj);
}


///

<summary>


///
从一个Json串生成对象信息

///

</summary>


///

<param name="jsonString"></param>


///

<param name="objType"></param>


///

<returns></returns>



public

static

object
JsonToObject(
string
jsonString, Type objType)
{

return
JavaScriptConvert.DeserializeObject(jsonString, objType);
}

}

这样就可以实现Json格式内容的发送和接受了。


使用测试客户端对数据进行测试,并调用ToString()生成接受到的数据内容,查看具体的内容,得到的效果如下所示。

标签: none

添加新评论