首页 > 学院 > 开发设计 > 正文

Unity中国象棋(五)——网络对战的实现(服务端的基本功能)

2019-11-06 09:32:47
字体:
来源:转载
供稿:网友

博主主要是用了socket的方法去实现了服务器和客户端之间的通信,由于楼主对于socket网络编程这一方面的基础相当薄弱,故也是边学边学,有些地方的代码不够完善还请大神指正!博主还需学习。

首先,先说说服务端方面:服务端采用的是VS的windows form窗体应用程序做的,也是为了方便查看和操作吧。

窗体长这样

首先先声明一个公共类

    public class Common    {        /// <summary>        /// 保存服务器来的消息        /// </summary>        public static byte[] ReceiveBuffer = new byte[1024 * 1024];        /// <summary>        /// 监听用的socket        /// </summary>        public static Socket ListenSocket;        /// <summary>        /// 保存所有负责通信用是socket        /// </summary>        public static Dictionary<string, Socket> connSocket = new Dictionary<string, Socket>();    }

服务端首先要开启服务,点击“启动服务器”按钮,则可以从两个TextBox中读取输入的ip地址和端口号的信息,通过这个信息开启服务

void StartServer()        {            try            {                string _ip = tbIp.Text;                int _point = int.Parse(tbPoint.Text);                //创建监听客户端请求的socket                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, PRotocolType.Tcp);                //监听用的ip和端口                IPAddress address = IPAddress.Parse(_ip);                IPEndPoint point = new IPEndPoint(address, _point);                //绑定                socket.Bind(point);                socket.Listen(10);                //异步 开始监听                socket.BeginAccept(new AsyncCallback(Listen), socket);                //禁用当前按钮                btnStart.Enabled = false;                //启动时间                startTime.Text = DateTime.Now.ToString();                //底部提示消息                tssMsg.Text = "服务器已经启动";            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);            }        }开启服务后,异步实现监听和接收消息,以保证服务器不会阻塞。

通过接收到的消息的头一个字节——协议位,来判断客户端发送的消息是要做什么的

        void Listen(IAsyncResult result)        {            try            {                //获取监听的socket                Socket clientSocket = result.AsyncState as Socket;                //与服务器通信的socket                Socket connSocket = clientSocket.EndAccept(result);                string ip = connSocket.RemoteEndPoint.ToString();                //连接成功。保存信息                if (!Common.connSocket.ContainsKey(ip))                    Common.connSocket.Add(ip, connSocket);                //连接成功,更新服务器信息                changeList(connSocket);                //等待新的客户端连接 ,相当于循环调用                clientSocket.BeginAccept(new AsyncCallback(Listen), clientSocket);                //接收来自客户端信息 ,相当于循环调用                connSocket.BeginReceive(Common.ReceiveBuffer, 0, Common.ReceiveBuffer.Length, 0, new AsyncCallback(Receive), connSocket);            }            catch (Exception ex)            {                MessageBox.Show(ex.Message);            }        }        void Receive(IAsyncResult result)        {            //与客户端通信的socket            Socket clientSocket = result.AsyncState as Socket;            string ip = clientSocket.RemoteEndPoint.ToString();            try            {                //获取实际的长度值                int num = clientSocket.EndReceive(result);                if (num > 0)                {                    byte[] data = new byte[num];                    //复制实际的长度到data字节数组中                    Array.Copy(Common.ReceiveBuffer, 0, data, 0, num);                    //判断协议位                    int command = data[0];                    switch (command)                    {                        case 1:                            //服务器保存发送方的IP和其棋子的颜色,并寻求配对                            MatchingRival(data,ip);                            break;                        case 2:                            //接收发送方发来的移动棋子的消息,并转发给接收方                            SendMoveMessageToClient(data);                            break;                        case 3:                            //接收发送方的悔棋消息,并转发给接收方                            SendRetractMessageToClient(data);                            break;                        case 6:                            //接收到发送方想要确定接收方是否在线的意愿,并做检测                            SendDisconnectMessageToClient(data);                            break;                        default:                            break;                    }                    //接收其他信息                    clientSocket.BeginReceive(Common.ReceiveBuffer, 0, Common.ReceiveBuffer.Length, 0, new AsyncCallback(Receive), clientSocket);                }                else //客户端断开                {                    clientOff(clientSocket);                }            }            catch (Exception ex)            {                clientOff(clientSocket);            }        }在介绍每一个从客户端接收的消息是干什么的之前(下一篇再整理),我们要先了解一下changeList(更新列表)和changOnlineCount(更新在线人数)这两个函数

        void changeList(Socket socket)        {            //获取客户端信息 ip和端口号            string ip = socket.RemoteEndPoint.ToString();            //客户端登陆时间            string time = DateTime.Now.ToString();            //跨线程操作ui            this.Invoke(new Action(() =>            {                //新增一行                dgvList.Rows.Add();                //获取当前dgvList的行                int rows = dgvList.Rows.Count;                //赋值                dgvList.Rows[rows - 1].Cells[0].Value = ip;                dgvList.Rows[rows - 1].Cells[1].Value = time;                //把ip当作当前行的tag标记一下,为了删除行的时候可以找到该行                dgvList.Rows[rows - 1].Tag = ip;                //更新在线人数                changOnlineCount(true);            }));        }        void changOnlineCount(bool tag)        {            int num = 0;            if (tag) num = int.Parse(lbCount.Text) + 1;            else num = int.Parse(lbCount.Text) - 1;            this.Invoke(new Action(() =>            {                //更新在线人数                lbCount.Text = num.ToString();                if (num == 0) Common.connSocket.Clear();            }));        }当有客户端连接的时候,首先会执行一次changeList函数,将所连接的客户端的信息显示在DataGridView里面,并在“在线人数”处+1

同样的,当有客户端断开的时候,也会更新列表,“在线人数”-1,删除在DataGridView里面的信息,并关闭该连接

        void clientOff(Socket clientSocket)        {            //从集合删除下线的ip            string outIp = clientSocket.RemoteEndPoint.ToString();            if (Common.connSocket.ContainsKey(outIp))                Common.connSocket.Remove(outIp);            //更新服务器在线人数            changOnlineCount(false);            this.Invoke(new Action(() =>            {                //更新列表                //删除退出的ip                for (int i = 0; i < dgvList.Rows.Count; i++)                {                    if (dgvList.Rows[i].Tag.ToString() == outIp)                    {                        dgvList.Rows.RemoveAt(i);                        break;                    }                }            }));            clientSocket.Shutdown(SocketShutdown.Receive);            clientSocket.Close();        }


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表