简单易懂的Socket TCP网络通讯知识-消息协议和数据包

不管用的是什么样的协议方式,基本通讯的原理
到底层 都是 byte[]数组 传递。

1.协议的定义
协议本身只是 通讯时候 前后端 定义的变量类型和顺序的集合。
比如说,要做一个登陆的消息传递,
需要传递的内容是帐号密码

public class MsgLogin
{
    public string m_strIDName = null;
    public string m_strPassWord = null;
}

前后端都确认好,使用帐号密码登陆,那么这样一个类,就可以称之为一个协议了。

那么客户端填好帐号密码后,转成byte[] 通过Socket发送到服务器,服务器解析这个消息,得到帐号密码,就完成了一次通讯。

byte[] 的内容就是 m_strIDName转换成的byte[] 拼接上 m_strPassWord转换成的byte[]

2.消息号
例如登入,客户端通知服务器要登录了
那么服务器对应的也要回复给客户端,登录是成功或者失败。
那么服务器可以定义通知客户端的协议是:

public class MsgLoginCallBack
{
	public bool m_isSuc = false;
}

那么问题就来了,一个游戏里,可以会有好多的通讯,比如购买,点击,广播之类的。 而消息本身只是一串byte[]的内容,
接受端要知道这条消息要干嘛,那就需要消息号。

消息号本身只需要做一个唯一的标记,例如可以做一个枚举:

public enum OperateCode : ushort
{
    C2S_LOGIN = 1,
    S2C_LOGIN = 2
}

C2S = Client to Server
S2C = Server to Client
(这个基本上约定俗成)
那么代码就变成了

public class MsgLogin
{
    public OperateCode m_opCode = OperateCode.C2S_LOGIN;
    public string m_strIDName = null;
    public string m_strPassWord = null;
}

public class MsgLoginCallBack
{
    public OperateCode m_opCode = OperateCode.S2C_LOGIN ;
	public bool m_isSuc = false;
}

客户端和服务器统一 一套消息号
这样互相解析第一个字段m_opCode 就能知道当前这条消息,对于本次通讯要做什么事了。
3.数据包的组装
前面说到通讯用到的是byte[]
那么怎么组装和解析这个byte[]那?
google的protobuf提供了很好的解决方案,可以百度一下参考。
这里说一下基本原理,也叫做 字节序,也是比较常用的一套方案。

先说一下消息包的组成。
一般分为 包头 和 包体。

包头 包含 消息号 和 包体长度
包体 包含 各种需要通讯的内容,也就是上面的类包含的变量。

例如:
包头部分:

内容类型长度
消息号ushort2
包体长度ushort2

那么包头的长度就是 2+2=4

包体:
像是上面的登录消息,是2个string,但是帐号密码的长度,我们是不知道的。那就需要做一件事就是 取得string的长度放在byte[]里string内容前面,告诉接收方,我接下去要解析的这个string字段的长度。

public class MsgLogin
{
    public string m_strIDName = null;
    public string m_strPassWord = null;
}

以这个消息为例
消息的构成就是

内容类型长度
消息号ushort2
包体长度ushortm_strIDName长度 + m_strPassWord长度
m_strIDName长度ushort转换byte[]后取长度
m_strIDName内容byte[]byte[]本身
m_strPassWord长度ushort转换byte[]后取长度
m_strPassWord内容byte[]byte[]本身
    public class MsgLogin
    {
        public OperateCode m_opCode = OperateCode.C2S_LOGIN;
        public string m_strIDName = null;
        public string m_strPassWord = null;

        public byte[] Package()
        {
            m_strIDName = "1234";
            m_strPassWord = "4321";

            byte[] bytesOpcode = BitConverter.GetBytes((ushort)m_opCode);
            byte[] bytesIDName = System.Text.Encoding.UTF8.GetBytes(m_strIDName);
            byte[] bytesPassWord = System.Text.Encoding.UTF8.GetBytes(m_strIDName);

            /*
            Buffer.BlockCopy拼接byte[]这里简写
            帐号长度 = bytesIDName.Length
            密码长度 = bytesPassWord.Length
            包体长度 = bytesIDName.Length + bytesPassWord.Length
            
            包头:[bytesOpcode + 包体长度]
            包体;[帐号长度 + bytesIDName + 密码长度 + bytesPassWord]
            
            消息包 = 包头 + 包体
             */
            return ***;
        }
    }

3.数据包的解析
最终得到byte[]发送,
接收到的时候
取得1,2位 解析 得到消息号
取得3,4位 解析 得到包体长度
按照包体长度向后取到整个包体
在包体中 解析 包体的1,2位解析得帐号(假定长度是ushort)

2(第一个string长度) + 帐号长度 + 1
2(第一个string长度) + 帐号长度 + 2
取得这2位 得到密码长度后,继续解析密码

这样一套 组装 和 解析的概念 就完成了。


程序学无止尽。
欢迎大家沟通,有啥不明确的,或者不对的,也可以和我私聊
我的QQ 334524067 神一般的狄狄

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值