一般公司的客户端上都会有协议模块,协议并非指TCP/UDP,而是用户层概念上的协议,用于区分字节流中每段字节的含义。
一般协议都是以这样的形式存在:协议号+用户数据
用户数据一般是以C#来说是结构体或类来表示,以lua来说是table表来表示。
socket套接字是传递字节流和接受字节流的(玩意),一般采用SocketType.Stream字节流形式传送和接受数据,底层协议可采用Tcp/Udp,关于其他详情可自行百度了解更多关于socket的知识点
在客户端上,一个协议会存在两个方法来进行对字节的封包和解包。
而区分每个协议的就是用(协议号),可理解为一个int
当服务器发送一个协议到客户端时,客户端socket接收到这串字节,然后你需要进行翻译成具体的数据,怎么翻译呢?
因为协议是有一部分字节是可以确定不变的,什么叫确定不变,就是比如:协议头部肯定是一个int(4个字节)代表协议号
那么我们就可以先翻译出协议号(取前4个字节转int),然后根据协议号找到对应的解包(翻译协议数据)的函数(方法),然后你就可以通过指定的方法,按(发包顺序)对数据字节数组进行翻译,最终得到这个协议的所有数据。
例如:服务器传了一个协议内容是(int)+(int, float, double) ,我不写具体数值,因为翻译只关心类型(字节长度),
可看见,第一个(int)是协议号,第二个(数据),这个数据顺序肯定是int -> float ->double ,这就是发包顺序。
那么翻译的时候,就必须要按照 int -> float -> double来翻译,不能打乱这个顺序!
这就是翻译流程(解包)。
客户端要向服务器发送数据前,你必须要为每个数据转化为字节,以字节数组形式通过客户端socket发送到服务器接收,因为你选的是字节流方式。
那么此时就要为每个数据进行一一转化,且顺序要确定!因为服务器要通过这个顺序来进行解包!
因此,我们也要为此做一个封包方法,针对不同的协议最好都做一个,因为需求可能会变化。
例如:首先协议号是确定的,一般是后台人员告诉你,你要用某个协议号进行发送,数据的结构也会由后台人员说明,
因为这些数据给服务器,服务器自然是后台人员去管理的,他们要解包,而他们为什么要你传数据给他呢,因为有需求,
这个需求一般是由后台定的。这样你就可以制作一个方法,来专门对要传递的数据进行封包,封包顺序一定要遵守数据的结构,
先是协议号,后是具体数据的封装,即具体数据转字节。
后续第二章会讲一下,如何封装指定长度的字符串string和解析指定长度字符串的问题 以及一些需要注意的问题,如粘包、字符编码、以及byte数组和委托的问题。