当前位置:   article > 正文

【Uinty】Socket聊天系统案例(妈宝级教程)_unity聊天系统

unity聊天系统

前言:很多人疑惑于Unity的网络游戏咋搞,从今起,我就将学习网络游戏编程的学习心得写于此(其实我也才刚刚学),分享给大家,希望对大家有所帮助。此篇文章是聊天系统,之后的状态同步与此都大同小异。

Unity测试视频:

网络笔记

目录

1.起步工作——Unity的聊天UI搭建

1.1创建两个Button、一个Inputfield和一个Text

 1.2创建控件脚本(该脚本后续也是客户端脚本)

 1.3为“连接”和“发送”按键绑定关键方法

2.异步の客户端

2.1关键方法a——Connection方法的搭建

2.2关键方法b——Send方法的搭建

3.异步の服务端

3.1

4.完善代码


1.起步工作——Unity的聊天UI搭建

1.1创建两个Button、一个Inputfield和一个Text

分别为两个Button子物体下的text命名为“连接”和“发送”(自己可以修改成自己喜欢的颜色和外DIY)

注意:这里的text和创建的Text是不同级别的,注意区分!

 1.2创建控件脚本(该脚本后续也是客户端脚本)

创建一个Script脚本组件随便挂载到一个物体上(笔者是选择挂在摄像头,它所含组件少些),拟出inputField和text,并将Unity中的Inputfield、Text物体挂上。

 

 1.3为“连接”和“发送”按键绑定关键方法

先在之前的脚本内添加Send方法和Connection方法,再在Unity中为两个Button绑定上预设方法。

 注意:此处的物体填入之前放置脚本的物体(我这里放置主摄像机)

2.异步の客户端

进入此之前,先普及一下异步通信,例如异步connect,其包含BeginConnect和EndConnect两个关键API,而BeginConnect中的参数包含一个AsyncCallback委托,即回调函数。而这个回调函数必须设有参数IAsyncResult。关于其有罗培羽老师做出的解释:(理解会用就行)

IAsyncResult是.NET提供的一种异步操作,通过名为Begin×××和End××x点的两个方法来实现原同步方法的异步调用。Begin×××方法包含同步方法中所需的参数,此外还包含另外两个参数:一个AsyncCallback委托和一个用户定义的状态对象。委托用来调用回调方法,状态对象用来向回调方法传递状态信息。且Begin×××方法返回一个实现IAsyncResult接口的对象,End×××方法用于结束异步操作并返回结果。End×××方法含有一个IAsyncResult参数,用于获取异步操作是否完成的信息,它的返回值与同步方法相同。
可完。

2.1关键方法a——Connection方法的搭建

打开脚本,为Connection()方法"生儿育女"。磨刀不误砍柴工,先上逻辑框架。

 注释:在Connection方法中,我们首先得创建一个Socket用于与服务端通信的一个客户端,然后通过API——BeginConnect连接服务器,在自定义的Connectcallback回调函数中使用BeginReceive来接收服务器的消息,并通过自定义的Receivecallback实现"接受循环"。紧接着,将异步Receive中获取的信息赋值给Text.text,从而同时实现消息的接受和展示。

接下来是代码展示:

  1. public void Connection()
  2. {
  3. //构建客户端Socket
  4. Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  5. //连接开始
  6. //"127.0.0.1"默认是本机IP。
  7. IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
  8. client.BeginConnect(iPEndPoint, Connectcallback, client);
  9. }
  10. public void Connectcallback(IAsyncResult ar)
  11. {
  12. try
  13. {
  14. Socket tempSocket = (Socket)ar.AsyncState;
  15. tempSocket.EndConnect(ar); //此处表示连接成功
  16. tempSocket.BeginReceive(readBuff, 0, 1024, 0, Receivecallback, tempSocket);
  17. }catch(SocketException ex)
  18. {
  19. Console.WriteLine("Error:" + ex);
  20. }
  21. }
  22. public void Receivecallback(IAsyncResult ar)
  23. {
  24. try
  25. {
  26. Socket tempSocket = (Socket)ar.AsyncState;
  27. int count = tempSocket.EndReceive(ar);
  28. massage = System.Text.Encoding.Default.GetString(readBuff, 0, count);
  29. //循环Receive
  30. tempSocket.BeginReceive(readBuff, 0, 1024, 0, Receivecallback, tempSocket);
  31. }
  32. catch (SocketException ex)
  33. {
  34. Console.WriteLine("Error:" + ex);
  35. }
  36. }
  37. private void Update()
  38. {
  39. //显示
  40. text.text = massage;
  41. }

2.2关键方法b——Send方法的搭建

同样的,先上逻辑框架。

 注释:在Send方法中,我们获取输入框的text文本,然后将文本的内容通过API——BeginSend发送给服务端,达到时刻等待用户的发送而不影响主程序的进行。

下面是代码展示:

  1. public void Send()
  2. {
  3. //发送消息
  4. string sendStr = inputField.text;
  5. byte[] sendByte = System.Text.Encoding.Default.GetBytes(sendStr);
  6. socket.BeginSend(sendByte, 0, sendByte.Length, 0, Sendcallback, socket);
  7. }
  8. //回调函数
  9. public void Sendcallback(IAsyncResult asyncResult)
  10. {
  11. try
  12. {
  13. Socket temporarySocket = (Socket)asyncResult.AsyncState;
  14. temporarySocket.EndSend(asyncResult);
  15. }
  16. catch (SocketException ex)
  17. {
  18. Debug.Log("失败:" + ex.ToString());
  19. }
  20. }

3.异步の服务端

3.1

相对于客户端,服务端相对复杂些。在此之前,我们先了解一下我们要使用的C#提供的一个集合体——Dictionary(字典),它是一个存储结构,包含两个字段,一个是‘Key’,另一个是‘Value’,它类似于我们的List。而字典的作用是用于管理与客户端通信的多个服务Sockets,而且有利于消息的广播。

先展示逻辑框架(字有点潦草。。。)

注释:在完成Bind、Listen进入监听状态后,我们使用API——BeginAccept获取连接,在自定义的回调函数Acceptcallback中实现异步Receive(用法与之前相同),与客户端不同,服务端的接收的消息是直接广播给全部客户端Socket的,因此我们要利用Dictionary来遍历所有的用于通信的serverSockets,来一一使用API——Send。

上码:

  1. //这里创造一个类用于封装serverSocket,有利于Dictionary的导入。
  2. class ClientState
  3. {
  4. public Socket socket;
  5. public byte[] readBuff = new byte[1024];
  6. }
  7. class Program
  8. {
  9. static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
  10. public static Socket acceptSocket;
  11. static void Main(string[] args)
  12. {
  13. Console.WriteLine("Welcome to Server!!!");
  14. //Socket
  15. Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
  16. IPAddress local_Ip = IPAddress.Parse("127.0.0.1");
  17. IPEndPoint iPEndPoint = new IPEndPoint(local_Ip, 8888);
  18. //绑定
  19. server.Bind(iPEndPoint);
  20. //Listen
  21. server.Listen(0);
  22. Console.WriteLine("[服务器]启动成功!");
  23. //接收客户端
  24. server.BeginAccept(Acceptcallback, server);
  25. Console.ReadLine();
  26. while (true)
  27. {
  28. //Accept
  29. Socket chat_socket = server.Accept();
  30. Console.WriteLine("服务器连接一名客户端:");
  31. //Receive
  32. byte[] readBuff = new byte[10240];
  33. int count = chat_socket.Receive(readBuff); //将Receive接收到的字节流保存在readBuff
  34. string massage = System.Text.Encoding.Default.GetString(readBuff, 0, count);
  35. Console.WriteLine("【服务器接收】" + massage);
  36. //Send
  37. byte[] sendBuff = System.Text.Encoding.Default.GetBytes(massage);
  38. chat_socket.Send(sendBuff);
  39. }
  40. }
  41. public static void Acceptcallback(IAsyncResult ar)
  42. {
  43. try
  44. {
  45. Console.WriteLine("客户端接入");
  46. Socket socket = (Socket)ar.AsyncState;
  47. Socket chatSocket = socket.EndAccept(ar);
  48. //列表导入
  49. ClientState state = new ClientState();
  50. state.socket = chatSocket;
  51. clients.Add(chatSocket, state);
  52. //接收数据
  53. chatSocket.BeginReceive(state.readBuff, 0, 1024, 0, Receivecallback, state);
  54. socket.BeginAccept(Acceptcallback, socket);
  55. }
  56. catch(SocketException ex)
  57. {
  58. Console.WriteLine("Error:" + ex.ToString());
  59. }
  60. }
  61. public static void Receivecallback(IAsyncResult ar)
  62. {
  63. try
  64. {
  65. ClientState clientState = (ClientState)ar.AsyncState;
  66. Socket clientfd = clientState.socket;
  67. int count = clientfd.EndReceive(ar);
  68. //判断客户端的断开
  69. if (count == 0)
  70. {
  71. clientfd.Close();
  72. clients.Remove(clientfd);
  73. Console.WriteLine("有客户端退出!");
  74. return;
  75. }
  76. string recvStr = System.Text.Encoding.Default.GetString(clientState.readBuff, 0, count);
  77. //将信息广播
  78. string time = System.DateTime.Now.ToString();
  79. byte[] vs = System.Text.Encoding.Default.GetBytes("[消息]:" + recvStr);
  80. foreach (ClientState item in clients.Values) //此处将clients中的所有clientstate遍历出来;
  81. {
  82. if(item.socket!=clientfd)
  83. item.socket.Send(vs);
  84. }
  85. clientfd.Send(vs);
  86. clientfd.BeginReceive(clientState.readBuff, 0, 1024, 0, Receivecallback, clientState);
  87. }
  88. catch (SocketException ex)
  89. {
  90. Console.WriteLine("error:" + ex.ToString());
  91. }
  92. }
  93. }

4.完善代码

为了使得客户端展示时只出现一句massage、同步时间等效果,笔者逐步完善服务端代码,展示如服务端代码区3.1。

PS:都看到这了,笔者写作不易呀,花费几天业余的时间创作,还请留下你的痕迹,接下来我会保持分享我学习网络游戏设计的心得!!!!

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/116856
推荐阅读
相关标签
  

闽ICP备14008679号