Unity3D游戏制作学习记录02——丛林战争

Siki学院的视频教程指路牌:http://www.sikiedu.com/course/61.

一、服务器端——消息接收的异步处理

由于之前使用Receive()方法来接受消息,是在等待消息的过程中一直执行,直到接收到消息了才会继续执行下面的代码,因此接收消息的方式是同步的。
这样的接收就只能一条一条的接收处理,不太符合实际的需求,所以就需要有异步的处理了。

异步处理调用的接收消息的方法是BeginReceive(),其中的参数是,接收到消息后会执行什么方法,由于这个方法的执行是不可知的,因此它是一个回调函数。

服务器端代码

class Program{static void Main(string[] args){StartServerAsync();}// 用于异步接收消息的数组static int bufferSize = 1024;static byte[] readBuf = new byte[bufferSize];/// <summary>/// 启动客户端,异步处理消息接收/// </summary>static void StartServerAsync(){//用于通信的套接字: IP类型,套接字类型:管道通信, 协议:TCPSocket serverScoket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 定义IPIPAddress ipAddress = IPAddress.Parse("127.0.0.1");int port = 7788;IPEndPoint iPEndPoint = new IPEndPoint(ipAddress, port);// 绑定IPserverScoket.Bind(iPEndPoint);// 开启监听serverScoket.Listen(0);// 等待连接,直到接收到连接请求Socket clientSocket = serverScoket.Accept();// 向客户端发送一条消息(二进制)string msgSend = "连接成功,服务器向客户端发送消息...";byte[] msgByt = System.Text.Encoding.UTF8.GetBytes(msgSend);clientSocket.Send(msgByt);// 异步接收// 读取的数据存储数组,存储的起始位置,存储数组的大小,套接字的标志位,接收到消息时要执行的函数,要给函数传递的信息clientSocket.BeginReceive(readBuf,0,1024,SocketFlags.None, ReceiveCallback, clientSocket);Console.ReadKey();}/// <summary>/// 回调函数,有消息接收的时候要进行的操作/// </summary>/// <param name="ar"></param>static void ReceiveCallback(IAsyncResult ar){// 转换传递的对象为客户端连接的套接字Socket clientSocket = (Socket)ar.AsyncState;// 结束消息接收,获取消息int count = clientSocket.EndReceive(ar);string msgRecv = System.Text.Encoding.UTF8.GetString(readBuf,0,count);Console.WriteLine("接收客户端消息:"+msgRecv);// 重新开启和客户端的消息接收clientSocket.BeginReceive(readBuf, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket);}}

客户端代码

我们通过死循环来实现客户端可以一直向服务器端发送消息。

static void Main(string[] args){//用于通信的套接字: IP类型,套接字类型:管道通信, 协议:TCPSocket socketClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 服务器请求连接客户端socketClient.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7788));// 客户端接收消息// 定义缓存区,存储接收到的服务器消息byte[] readBuf = new byte[1024];int count = socketClient.Receive(readBuf);string msgRecv = System.Text.Encoding.UTF8.GetString(readBuf, 0, count);// 将消息显示在控制台上Console.WriteLine(msgRecv);while (true){// 客户端向服务器发送消息,发送的消息由用户在控制台输入string msgSend = Console.ReadLine();socketClient.Send(System.Text.Encoding.UTF8.GetBytes(msgSend));}Console.ReadKey();// 关闭连接socketClient.Close();}

二、服务器端——多客户端连接

多客户端的连接我们同样是采取异步处理的方式,即BeginAccept()方法。
BeginAccept():它的参数有两个,一个是接收到连接请求的时候,要执行的函数,另一个是执行函数的时候要传递的内容。

同样这个要执行的函数也是回调函数,我们把客户端连接的获取,以及消息的收发都写在这个函数里面。

由于在BeginAccept()获取连接之后,消息收发都在获取连接的回调函数AcceptCallback()内执行,但在AcceptCallback()内,我们暂时的关闭了连接用以获取当前的客户端连接,所以我们需要在消息处理完后,重新开启连接接收,才能继续接收客户端连接申请。

服务器端代码

class Program{static void Main(string[] args){StartServerAsync();}// 用于异步接收消息的数组static int bufferSize = 1024;static byte[] readBuf = new byte[bufferSize];/// <summary>/// 启动客户端,异步处理消息接收/// </summary>static void StartServerAsync(){//用于通信的套接字: IP类型,套接字类型:管道通信, 协议:TCPSocket serverScoket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);// 定义IPIPAddress ipAddress = IPAddress.Parse("127.0.0.1");int port = 7788;IPEndPoint iPEndPoint = new IPEndPoint(ipAddress, port);// 绑定IPserverScoket.Bind(iPEndPoint);// 开启监听serverScoket.Listen(0);// 异步处理客户端的连接serverScoket.BeginAccept(AcceptCallback, serverScoket);Console.ReadKey();}/// <summary>/// 回调函数,有连接请求时要进行的操作/// </summary>/// <param name="ar"></param>static void AcceptCallback(IAsyncResult ar){// 获取服务器端Socket serverSocket = ar.AsyncState as Socket;// 关闭连接接收,获取当前客户端连接Socket clientSocket =  serverSocket.EndAccept(ar);// 向客户端发送一条消息(二进制)string msgSend = "连接成功,服务器向客户端发送消息...";byte[] msgByt = System.Text.Encoding.UTF8.GetBytes(msgSend);clientSocket.Send(msgByt);// 异步接收客户端的消息// 读取的数据存储数组,存储的起始位置,存储数组的大小,套接字的标志位,接收到消息时要执行的函数,要给函数传递的信息clientSocket.BeginReceive(readBuf, 0, 1024, SocketFlags.None, ReceiveCallback, clientSocket);// 重新开启连接接收serverSocket.BeginAccept(AcceptCallback,serverSocket);}/// <summary>/// 回调函数,有消息接收的时候要进行的操作/// </summary>/// <param name="ar"></param>static void ReceiveCallback(IAsyncResult ar){// 转换传递的对象为客户端连接的套接字Socket clientSocket = (Socket)ar.AsyncState;// 结束消息接收,获取消息int count = clientSocket.EndReceive(ar);string msgRecv = System.Text.Encoding.UTF8.GetString(readBuf,0,count);Console.WriteLine("接收客户端消息:"+ msgRecv);// 重新开启和客户端的消息接收clientSocket.BeginReceive(readBuf, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket);}}

运行结果

  1. 运行服务器端

  2. 运行客户端1

  3. 运行客户端2

  4. 客户端2向服务器端发送消息

  5. 客户端1向服务器端发送消息

代码完善

在服务器端仍然开启,但关闭客户端的时候,会出现报错,

像这样子:

或者这样子:

这是由于客户端的不正常关闭导致哒。
那么我们就在服务器端通过异常来捕获它,并从服务器端这一侧来关闭连接。

 /// <summary>/// 回调函数,有消息接收的时候要进行的操作/// </summary>/// <param name="ar"></param>static void ReceiveCallback(IAsyncResult ar){Socket clientSocket = null;try{// 转换传递的对象为客户端连接的套接字clientSocket = (Socket)ar.AsyncState;// 结束消息接收,获取消息int count = clientSocket.EndReceive(ar);string msgRecv = System.Text.Encoding.UTF8.GetString(readBuf, 0, count);Console.WriteLine("接收客户端消息:" + msgRecv);// 重新开启和客户端的消息接收clientSocket.BeginReceive(readBuf, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket);}catch(Exception e){Console.WriteLine(e);if (clientSocket != null){clientSocket.Close();}}            }

但是,如果我给客户端加一个标识,比如说按下c键,就从客户端侧关闭连接,此时服务器端会一直接受到长度为0的空消息。
那是否我在客户端控制台输入回车也会表示发送空数据呢,并不是的,因为即使回车也是一个‘\n’,看上去是空但并不是空。
所以我们可以在服务器端接收消息的时候判断接收到的数据是否长度为0,如果是就可以直接断开和客户端的连接了。

 try{// 转换传递的对象为客户端连接的套接字clientSocket = (Socket)ar.AsyncState;// 结束消息接收,获取消息int count = clientSocket.EndReceive(ar);if (count == 0){clientSocket.Close();}string msgRecv = System.Text.Encoding.UTF8.GetString(readBuf, 0, count);Console.WriteLine("接收客户端消息:" + msgRecv);// 重新开启和客户端的消息接收clientSocket.BeginReceive(readBuf, 0, bufferSize, SocketFlags.None, ReceiveCallback, clientSocket);}

Unity3D游戏制作学习记录02——丛林战争相关推荐

  1. Unity3D游戏制作学习记录01——丛林战争

    Unity3D游戏制作学习记录01--丛林战争 Siki学院的视频教程指路牌:http://www.sikiedu.com/course/61. 学业繁忙-和朋友一起跟着siki的丛林战争的教程跟着做 ...

  2. 游戏制作-联网对战丛林战争制作笔记(一)

    开篇先说明,这个游戏制作也是我跟随别人的教程制作的游戏,因此想要了解更多的内容可以去看siki老师的视频,我这里做笔记的目的有两个,一个是帮助喜欢看文字版教程的朋友进一步的学习,一个是保存自己在学习中 ...

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

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

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

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

  5. [整理]Unity3D游戏开发之Lua

    原文1:[Unity3D]Unity3D游戏开发之Lua与游戏的不解之缘(上) 各位朋友,大家好,我是秦元培,欢迎大家关注我的博客,我地博客地址是blog.csdn.net/qinyuanpei.如果 ...

  6. unity网络实战开发(丛林战争)-正式开发阶段(016-数据库设计以及登录处理)

    使用工具:VS2017,unity3d 使用语言:c# 作者:Gemini_xujian 参考:siki老师-<丛林战争>视频教程 上一篇文章中,已经完成了游戏场景与开始界面UI的搭建,接 ...

  7. Unity3D 游戏引擎之脚本实现模型的平移与旋转(六)

    Unity3D 游戏引擎之脚本实现模型的平移与旋转 雨松MOMO原创文章如转载,请注明:转载至我的独立域名博客雨松MOMO程序研究院,原文地址:http://www.xuanyusong.com/ar ...

  8. Unity3D 游戏引擎之IOS高级界面发送消息与Unity3D消息的接收(九)

    Unity3D 游戏引擎之IOS高级界面发送消息与Unity3D消息的接收 雨松MOMO原创文章如转载,请注明:转载自雨松MOMO的博客原文地址:http://blog.csdn.net/xys289 ...

  9. Unity3D游戏开发-宣雨松读书摘要(2015-4-17 18:36)

    本书基于Unity3.5编写,通过丰富的游戏实例,以JavaScript与C#两种语言介绍Unity开发. Unity3D游戏开发-宣雨松 序 它支持JavaScript.C#.Boo三种脚本语言 ...

最新文章

  1. D - Bear and Finding Criminals
  2. Kafka坑 - Couldn't find leaders for Set(kafka重启)
  3. 电商、快递最后一公里的解决方案
  4. 7nm芯片计划受挫 英特尔股价周五收盘暴跌16.24%
  5. Flutter进阶—质感设计之直接输入
  6. 安卓开发课程设计报告
  7. 2019上半年系统集成项目管理工程师上午真题及答案解析
  8. 萌新日记一:安装SQL Server 2012遇见windows安装NETFX3失败
  9. 商业杂志图表的经典用色
  10. Elasticsearch对接Django
  11. 整车EMC正向开发及仿真
  12. lol手游日服服务器未响应,LOL手游进不去怎么回事?日服登陆失败解决办法[多图]...
  13. NFA到DFA的子集构造法
  14. Java获得随机数的几种方法
  15. 直播安全体系、播放安全、推流安全以及内容安全方案分享
  16. Intel有那些45纳米的CPU
  17. 虚幻引擎 4 14 版发布
  18. System.Diagnostics.Process执行获取程序实时输出消息
  19. ife2018 零基础学院 day 3
  20. 什么是元组以及元组的作用

热门文章

  1. tkinter canvas jpg_1分钟教你将JPG图片转为CAD文件,简单到没朋友,小白必看
  2. 编写frame.java_returnordersubmitframe.java~83~ 源代码在线查看 - 用java编写的进销存系统 资源下载 虫虫电子下载站...
  3. dayjs 中文文档
  4. 怎样反汇编bzImage
  5. 舞动的表情包——浅析 GIF 格式图片的存储和压缩
  6. C++ 中的  EOF
  7. 基于SpringBoot+TestNG框架接口自动化环境搭建
  8. 算术编码二进制例题a1a2a3a4_Chap5_思考题与习题.pdf
  9. 基于Java办公自动化系统(OA)的设计技术及开发环境
  10. 三极管工作原理_【电子器件】02:三极管工作原理