使用工具:VS2015

使用语言:c#

作者:Gemini_xujian

参考:siki老师-《丛林战争》视频教程

继上一篇文章内容,这节课讲解一下在服务器端解析数据。

首先,同前文类同,先创建一个Message类,用来存储和解析客户端发送过来的数据,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace C_Sharp游戏服务器端编程
{class Message{private byte[] data = new byte[1024];//用来存储现在的数据,需要足够大private int startIndex = 0;//用来保存当前已经存取的数据位置public byte[] Data{get{return data;}}public int StartIndex{get{return startIndex;}}public int RemainSizs{get{return data.Length - startIndex;}}//更新索引public void AddCount(int count){startIndex += count;}/// <summary>/// 解析数据/// </summary>public void ReadMessage(){while (true){if (startIndex <= 4) return;int count = BitConverter.ToInt32(data, 0);if (startIndex - 4 >= count){string s = Encoding.UTF8.GetString(data, 4, count);Array.Copy(data, 4, data, 0, startIndex - 4 - count);startIndex -= count + 4;}else{break;}}}}
}

在这个Message类中,首先定义了几个属性和字段,其中,data表示的是保存数据用的字节数组,它的字节长度一定要足够大,startindex表示当前已经存取数据的位置,也可以理解为当前data字节数组的大小,RemainSize()表示data数组剩余的存储空间大小,AddCount()用来每次将数据放入data数组后对startindex值进行更新。使用ReadMessage()方法对每次传递过来的数据进行解析。这个方法主要处理的是粘包问题。

ReadMessage()方法的逻辑思路如下:首先判断当前存取数据长度是否大于4字节,如果小于等于四字节则直接返回;然后获取data数组中的数据所存储的字节长度为多少,之后通过判断条件判断当前已存储数据长度减去四个字节(这四个字节用作了存储数据已使用长度信息)是否大于等于count值,即读取到的四字节长度信息,如果为true,则将data中从第四个字节开始长度为count的数据读取出来,这是一条信息数据;然后通过调用Array.copy()方法将data数组已读取完成的部分去掉,并将startindex值做出相应改变,如果之前的判断条件不成立则直接break掉,这个方法也就执行结束了。

而在服务器端主逻辑端,也就是Program类中,需要做一些修改,代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;//引入的命名空间
using System.Net.Sockets;//引入的命名空间
using System.Text;
using System.Threading.Tasks;namespace C_Sharp游戏服务器端编程
{class Program{static void Main(string[] args){StartReceiveAsync();Console.ReadKey();}static void StartReceiveAsync(){Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个socket对象,第一个参数表示IP,第二个参数表示使用流(相当于管道),第三个参数表示使用tcp协议//IPAddress ipAdress = new IPAddress(new byte[] { 127,0,0,1 });IPAddress ipAdress = IPAddress.Parse("127.0.0.1");//创建一个ip地址IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 6789);serverSocket.Bind(ipEndPoint);//绑定IP和端口号serverSocket.Listen(0);//开始监听端口号,参数设置为0表示不对连接数做限制,填其他数字则表示最大连接数//Socket clientSocket = serverSocket.Accept();//接收一个客户端的连接serverSocket.BeginAccept(AcceptCallBack, serverSocket);}static Message msg = new Message();//异步连接客户端的回调函数static void AcceptCallBack(IAsyncResult ar){Socket serverSocket = ar.AsyncState as Socket;Socket clientSocket = serverSocket.EndAccept(ar);string msgStr = "hello 你好...";byte[] data = Encoding.UTF8.GetBytes(msgStr);//将字符串转换成byte数组clientSocket.Send(data);//向客户端发送一条信息clientSocket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSizs, SocketFlags.None, ReceiveCallBack, clientSocket);serverSocket.BeginAccept(AcceptCallBack, serverSocket);//继续处理下一个客户端的连接}static byte[] dataBuff = new byte[1024];static  void ReceiveCallBack(IAsyncResult ar){Socket clientSocket = null;try{clientSocket = ar.AsyncState as Socket;int count = clientSocket.EndReceive(ar);if(count==0){clientSocket.Close();return;}msg.AddCount(count);msg.ReadMessage();//Console.WriteLine(Encoding.UTF8.GetString(dataBuff), 0, count);//clientSocket.BeginReceive(dataBuff, 0, 1024, SocketFlags.None, ReceiveCallBack, clientSocket);clientSocket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSizs, SocketFlags.None, ReceiveCallBack, clientSocket);}catch (Exception e){Console.WriteLine(e);if (clientSocket != null){clientSocket.Close();}}}void StartReceiveSync(){Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建一个socket对象,第一个参数表示IP,第二个参数表示使用流(相当于管道),第三个参数表示使用tcp协议//IPAddress ipAdress = new IPAddress(new byte[] { 127,0,0,1 });IPAddress ipAdress = IPAddress.Parse("127.0.0.1");//创建一个ip地址IPEndPoint ipEndPoint = new IPEndPoint(ipAdress, 6789);serverSocket.Bind(ipEndPoint);//绑定IP和端口号serverSocket.Listen(0);//开始监听端口号,参数设置为0表示不对连接数做限制,填其他数字则表示最大连接数Socket clientSocket = serverSocket.Accept();//接收一个客户端的连接string msg = "hello 你好...";byte[] data = Encoding.UTF8.GetBytes(msg);//将字符串转换成byte数组clientSocket.Send(data);//向客户端发送一条信息byte[] dataBuffer = new byte[1024];//创建一个byte数组用来接收数据int count = clientSocket.Receive(dataBuffer);//接收客户端发送过来的数据,返回值是数据长度string msgReceive = Encoding.UTF8.GetString(dataBuffer, 0, count);//将接收到的byte数组转换成字符串Console.WriteLine(msgReceive);//在控制台输出一下发送过来的数据Console.ReadKey();clientSocket.Close();//关闭与客户端的连接serverSocket.Close();//关闭自身的连接 }}
}

在这个类中,主要改了接收客户端发送过来的数据的处理,首先是定义了一个Message类,然后将BeginReceive()中的一些参数用message类的实例进行了替换,并在数据接收的回调函数中进行了message类中startindex数值的更新和解析数据方法的调用。至此,一个服务器与多客户端连接以及多消息收发解析功能就实现了。

unity网络实战开发(丛林战争)-前期知识准备(010-在服务器端解析数据)相关推荐

  1. unity网络实战开发(丛林战争)-前期知识准备(012-UI框架开发)

    使用工具:VS2017,Unity2017.3,DoTween插件 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解 ...

  2. unity网络实战开发(丛林战争)-前期知识准备(011-c#连接数据库并实现增删改查以及sql注入问题)

    使用工具:VS2015,Mysql 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下数据库的前期连接准备以及通过 ...

  3. unity网络实战开发(丛林战争)-前期知识准备(004-开发TCP客户端的接收数据和发送数据)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下客户端的接收数据和发送数据. 首先在现有 ...

  4. unity网络实战开发(丛林战争)-前期知识准备(006-修改服务器端开启异步处理客户端连接请求)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下修改服务器开启一步处理客户端连接请求. ...

  5. unity网络实战开发(丛林战争)-前期知识准备(008-粘包和分包及解决方案)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下什么是粘包和分包,以及处理粘包和分包问题 ...

  6. unity网络实战开发(丛林战争)-前期知识准备(003-开发服务器端的发送数据和接收数据)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下服务器端的发送数据和接收数据. 上篇文章 ...

  7. unity网络实战开发(丛林战争)-正式开发阶段(013-游戏服务器端框架搭建)

    使用工具:VS2015 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 继上一篇文章内容,这节课讲解一下游戏服务器端的开发. 01-项目目录结构 ...

  8. unity网络实战开发(丛林战争)-正式开发阶段(014-游戏客户端与服务器端连接搭建)

    使用工具:VS2017,unity3d 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 上一篇文章中,我已经把服务器端的框架进行了搭建,接下来, ...

  9. unity网络实战开发(丛林战争)-正式开发阶段(018-声音管理器模块的完善)

    使用工具:VS2017,unity3d 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 上一篇文章中,已经完成了注册事件的处理,接下来将完善声音 ...

最新文章

  1. java枚举体_Java枚举体
  2. SQL Server中执行正则表达式
  3. Smarty变量调节器的使用
  4. CF 2B.The least round way
  5. java程序猿面试问缺点怎么回答_JAVA程序员面试32问,你能回答多少题
  6. Linux 服务器远程控制三剑客Telnet、SSH 和 VNC 之 VNC
  7. appium for java教程_appium自动化测试入门(java版)
  8. ubuntu openssl1.0.2g交叉编译
  9. 02-07 Python库-pytest
  10. Compass的误解与新发现
  11. 如何手动养成一只「咖啡女仆」?丨全套攻略+材料清单
  12. java反射用法示例_Java反射示例教程
  13. 美国国际集团(AIG-American International Group)
  14. Python Tkinter 项目实例:小说在线阅读器(爬虫部分已过期)
  15. Cadence PSpice 仿真6:反向放大器傅里叶仿真(FFT,谐波分析)实战图文教程
  16. 刚毕业一个月,7 月正式入职深圳互联网公司的前端月度工作汇报 |总结
  17. YOLOv5-优化器和学习率调整策略
  18. Properties综合应用,冲冲冲
  19. 2021清远市清城中学高考成绩查询,清远市清城中学中考成绩
  20. 分布式一致性算法—— 2PC与3PC

热门文章

  1. 计算机vb基础知识,计算机二级VB考试基础知识
  2. lede 增加新固件型号
  3. SNS游戏中社区Server和游戏Server一种数据交互的策略
  4. 是一种心灵的默契,爱一个人不一定要拥有
  5. 树莓派魔镜php,手把手教你打造属于自己的树莓派魔镜
  6. 金工如何运用计算机思维,金工实训心得体会
  7. systemctl 实现开机自启服务
  8. unity3D多媒体展厅触摸屏互动程序
  9. windows 找不到文件 ‘C:\ApplicationC\UltraEdit24_18212\UltraEdit24.20.0.40(x64)\UltraEdit\uedit32.exe’
  10. haproxy和oracle,IRF虚拟化技术介绍