服务端框架中重要的一个模块,单独开一节详谈。
上一节中提到,所有协议都从字节流中读取消息,又把某种形式的消息转换为字节流发送出去。
所以,只要定义好编码解码的接口,便能够支持多种协议。而一套通用的服务端框架,要支持不同的游戏使用的各种协议格式。下面先从一些基本知识讲起。
####1.粘包分包现象及其处理
由于TCP协议本身的机制,客户端和服务器会维持一个连接发送数据。如果发送的网络数据包大小,TCP则会合并较小的数据包再发送;类似地,如果发送的数据包太大,TCP有可能会将它拆分成多个包发送,接收端的一次Receive可能只收到一部分数据。这便是粘包分包现象。
这里使用一种比较好理解的处理方法,即在每个数据包前面加上长度字节。每次接收到数据后,先读取长度字节,如果缓冲区的数据长度大于要提取的字节数,则取出相应的字节,否则等待下一次数据接收。
####2.协议基类
我们将一次发送的完整数据称为消息,将消息内容称为协议内容。由上文所述,一条消息的前四个字节用于粘包分包处理消息长度,随后才是消息内容。
服务端框架使用了两层协议:一层用于处理底层网络,另一层用于格式化数据。
协议基类ProtocolBase定义协议接口,其他协议类型必须继承ProtocolBase。通用的接口包括编码、解码、获取协议名称和用于打印输出的描述。
//协议基类
//规定协议中编码、解码等方法的格式
public class ProtocolBase
{
//解码器,解码readbuff中从start开始的length字节
public virtual ProtocolBase Decode(byte[] readbuff, int start, int length)
{
return new ProtocolBase ();
}
//编码器
public virtual byte[] Encode()
{
return new byte[] { };
}
//协议名称,用于消息分发
public virtual string GetName()
{
return "";
}
//描述
public virtual string GetDesc()
{
return "";
}
public ProtocolBase ()
{
}
}
####3.字符串协议
这种协议即是上一篇文章中所实现的,特点是直观、简单。我们规定字符串协议的形式是“参数1 参数2 参数3…”我们规定参数1是协议名称,且各个参数之间用空格隔开。但缺点是,客户端若发送了含有空格符的字符串,就会引起混淆。
//基于字符串的协议
//形式 名称 参数1 参数2 参数3
public class ProtocolStr : ProtocolBase
{
//传输的字符串
//整个协议都用字符串表达
public string str;
//解码器
//解码过程便是将字节流转换成字符串
public override ProtocolBase Decode(byte[] readbuff, int start, int length)
{
ProtocolStr protocol = new ProtocolStr ();
protocol.str = System.Text.Encoding.UTF8.GetString (readbuff, start, length);
return (ProtocolBase)protocol;
}
//编码器
//编码过程便是将字符串转换为字节流
public override byte[] Encode()
{
byte[] b = System.Text.Encoding.UTF8.GetBytes (str);
return b;
}
//协议名称
//获取第一个空格前的字符串,即为协议名称
public override string GetName()
{
if (str.Length == 0)
return "";
return str.Split (' ') [0];
}
//描述
//用字符串代表协议描述
public override string GetDesc()
{
return str;
}
public ProtocolStr ()
{
}
}
####4.字节流协议
字节流协议是一种最基本的协议。它把所有参数放入byte[]结构中,客户端和服务端按照约定的数据类型和顺序解析各个参数。本节编写的字节流协议支持整型、浮点型和字符串三种数据类型。我们规定协议的第一个参数必须是字符串,它代表协议名称。
这种协议的好处是,只要客户端和服务端按照约定好的类型进行读取,总能够正确地解析出各个参数。
####5.心跳协议
正常情况下,断开TCP会经历四次挥手。然而如果客户端电脑死机,或者网线被拔出,四次挥手便无法完成。服务器在同一时间能够接入的客户端数量是有限的,如果出现太多这样的死连接,新连接便无法接入。
为了防止出现上述情况,引入了心跳机制。心跳机制规定客户端每隔一定时间要给服务器发送一个特定信号,服务器会记录客户端最后一次发送心跳信号的时间,如果相隔太久,便认为客户端连接已经断开,于是主动断开连接。
参考资料:《Unity3D 网络游戏实战》罗培羽·著
明天是这周实训的最后一天,下周就要开始答辩。希望能够把能做的模块都做好。
明日目标:完成卡牌部分的数据库更新。