赞
踩
前言:很多人疑惑于Unity的网络游戏咋搞,从今起,我就将学习网络游戏编程的学习心得写于此(其实我也才刚刚学),分享给大家,希望对大家有所帮助。此篇文章是聊天系统,之后的状态同步与此都大同小异。
Unity测试视频:
网络笔记
目录
1.1创建两个Button、一个Inputfield和一个Text
分别为两个Button子物体下的text命名为“连接”和“发送”(自己可以修改成自己喜欢的颜色和外DIY)
注意:这里的text和创建的Text是不同级别的,注意区分!
创建一个Script脚本组件随便挂载到一个物体上(笔者是选择挂在摄像头,它所含组件少些),拟出inputField和text,并将Unity中的Inputfield、Text物体挂上。
先在之前的脚本内添加Send方法和Connection方法,再在Unity中为两个Button绑定上预设方法。
注意:此处的物体填入之前放置脚本的物体(我这里放置主摄像机)
进入此之前,先普及一下异步通信,例如异步connect,其包含BeginConnect和EndConnect两个关键API,而BeginConnect中的参数包含一个AsyncCallback委托,即回调函数。而这个回调函数必须设有参数IAsyncResult。关于其有罗培羽老师做出的解释:(理解会用就行)
IAsyncResult是.NET提供的一种异步操作,通过名为Begin×××和End××x点的两个方法来实现原同步方法的异步调用。Begin×××方法包含同步方法中所需的参数,此外还包含另外两个参数:一个AsyncCallback委托和一个用户定义的状态对象。委托用来调用回调方法,状态对象用来向回调方法传递状态信息。且Begin×××方法返回一个实现IAsyncResult接口的对象,End×××方法用于结束异步操作并返回结果。End×××方法含有一个IAsyncResult参数,用于获取异步操作是否完成的信息,它的返回值与同步方法相同。
可完。
打开脚本,为Connection()方法"生儿育女"。磨刀不误砍柴工,先上逻辑框架。
注释:在Connection方法中,我们首先得创建一个Socket用于与服务端通信的一个客户端,然后通过API——BeginConnect连接服务器,在自定义的Connectcallback回调函数中使用BeginReceive来接收服务器的消息,并通过自定义的Receivecallback实现"接受循环"。紧接着,将异步Receive中获取的信息赋值给Text.text,从而同时实现消息的接受和展示。
接下来是代码展示:
-
- public void Connection()
- {
- //构建客户端Socket
- Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- //连接开始
- //"127.0.0.1"默认是本机IP。
- IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
- client.BeginConnect(iPEndPoint, Connectcallback, client);
- }
- public void Connectcallback(IAsyncResult ar)
- {
- try
- {
- Socket tempSocket = (Socket)ar.AsyncState;
- tempSocket.EndConnect(ar); //此处表示连接成功
- tempSocket.BeginReceive(readBuff, 0, 1024, 0, Receivecallback, tempSocket);
-
- }catch(SocketException ex)
- {
- Console.WriteLine("Error:" + ex);
- }
-
- }
- public void Receivecallback(IAsyncResult ar)
- {
- try
- {
- Socket tempSocket = (Socket)ar.AsyncState;
- int count = tempSocket.EndReceive(ar);
- massage = System.Text.Encoding.Default.GetString(readBuff, 0, count);
-
- //循环Receive
- tempSocket.BeginReceive(readBuff, 0, 1024, 0, Receivecallback, tempSocket);
-
- }
- catch (SocketException ex)
- {
- Console.WriteLine("Error:" + ex);
- }
-
- }
-
- private void Update()
- {
- //显示
- text.text = massage;
- }

同样的,先上逻辑框架。
注释:在Send方法中,我们获取输入框的text文本,然后将文本的内容通过API——BeginSend发送给服务端,达到时刻等待用户的发送而不影响主程序的进行。
下面是代码展示:
- public void Send()
- {
- //发送消息
- string sendStr = inputField.text;
- byte[] sendByte = System.Text.Encoding.Default.GetBytes(sendStr);
- socket.BeginSend(sendByte, 0, sendByte.Length, 0, Sendcallback, socket);
-
-
- }
- //回调函数
- public void Sendcallback(IAsyncResult asyncResult)
- {
- try
- {
- Socket temporarySocket = (Socket)asyncResult.AsyncState;
- temporarySocket.EndSend(asyncResult);
-
- }
- catch (SocketException ex)
- {
- Debug.Log("失败:" + ex.ToString());
-
- }
- }

相对于客户端,服务端相对复杂些。在此之前,我们先了解一下我们要使用的C#提供的一个集合体——Dictionary(字典),它是一个存储结构,包含两个字段,一个是‘Key’,另一个是‘Value’,它类似于我们的List。而字典的作用是用于管理与客户端通信的多个服务Sockets,而且有利于消息的广播。
先展示逻辑框架(字有点潦草。。。)
注释:在完成Bind、Listen进入监听状态后,我们使用API——BeginAccept获取连接,在自定义的回调函数Acceptcallback中实现异步Receive(用法与之前相同),与客户端不同,服务端的接收的消息是直接广播给全部客户端Socket的,因此我们要利用Dictionary来遍历所有的用于通信的serverSockets,来一一使用API——Send。
上码:
- //这里创造一个类用于封装serverSocket,有利于Dictionary的导入。
- class ClientState
- {
- public Socket socket;
- public byte[] readBuff = new byte[1024];
- }
- class Program
- {
- static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
- public static Socket acceptSocket;
- static void Main(string[] args)
- {
-
- Console.WriteLine("Welcome to Server!!!");
- //Socket
- Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
- IPAddress local_Ip = IPAddress.Parse("127.0.0.1");
- IPEndPoint iPEndPoint = new IPEndPoint(local_Ip, 8888);
- //绑定
- server.Bind(iPEndPoint);
- //Listen
- server.Listen(0);
- Console.WriteLine("[服务器]启动成功!");
-
- //接收客户端
- server.BeginAccept(Acceptcallback, server);
- Console.ReadLine();
-
- while (true)
- {
- //Accept
- Socket chat_socket = server.Accept();
- Console.WriteLine("服务器连接一名客户端:");
- //Receive
- byte[] readBuff = new byte[10240];
- int count = chat_socket.Receive(readBuff); //将Receive接收到的字节流保存在readBuff
- string massage = System.Text.Encoding.Default.GetString(readBuff, 0, count);
-
- Console.WriteLine("【服务器接收】" + massage);
-
- //Send
- byte[] sendBuff = System.Text.Encoding.Default.GetBytes(massage);
- chat_socket.Send(sendBuff);
- }
- }
- public static void Acceptcallback(IAsyncResult ar)
- {
- try
- {
- Console.WriteLine("客户端接入");
- Socket socket = (Socket)ar.AsyncState;
- Socket chatSocket = socket.EndAccept(ar);
- //列表导入
- ClientState state = new ClientState();
- state.socket = chatSocket;
- clients.Add(chatSocket, state);
- //接收数据
- chatSocket.BeginReceive(state.readBuff, 0, 1024, 0, Receivecallback, state);
- socket.BeginAccept(Acceptcallback, socket);
- }
- catch(SocketException ex)
- {
- Console.WriteLine("Error:" + ex.ToString());
- }
- }
- public static void Receivecallback(IAsyncResult ar)
- {
- try
- {
- ClientState clientState = (ClientState)ar.AsyncState;
- Socket clientfd = clientState.socket;
- int count = clientfd.EndReceive(ar);
- //判断客户端的断开
- if (count == 0)
- {
- clientfd.Close();
- clients.Remove(clientfd);
- Console.WriteLine("有客户端退出!");
- return;
- }
- string recvStr = System.Text.Encoding.Default.GetString(clientState.readBuff, 0, count);
- //将信息广播
- string time = System.DateTime.Now.ToString();
- byte[] vs = System.Text.Encoding.Default.GetBytes("[消息]:" + recvStr);
- foreach (ClientState item in clients.Values) //此处将clients中的所有clientstate遍历出来;
- {
- if(item.socket!=clientfd)
- item.socket.Send(vs);
- }
- clientfd.Send(vs);
- clientfd.BeginReceive(clientState.readBuff, 0, 1024, 0, Receivecallback, clientState);
- }
- catch (SocketException ex)
- {
- Console.WriteLine("error:" + ex.ToString());
- }
- }
- }

为了使得客户端展示时只出现一句massage、同步时间等效果,笔者逐步完善服务端代码,展示如服务端代码区3.1。
PS:都看到这了,笔者写作不易呀,花费几天业余的时间创作,还请留下你的痕迹,接下来我会保持分享我学习网络游戏设计的心得!!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。