使用C# SocketTCP开发网络游戏ForestWars(三) 创建连接类,实现多个客户端的连接与管理

版权声明:未经同意,请勿转载 https://blog.csdn.net/qq_25542475/article/details/86790203
本章主要讲述服务端通过创建连接类,实现多个客户端的连接管理。

一 为什么创建连接类

服务端要处理多个客户端消息,它需要用一个数组来维护所有客户端的连接。每个客户端都有自己的Socket以及缓冲区。

二 业务逻辑的实现

(1)创建Conn连接类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using TCP_Sever.Timer;

namespace TCP_Sever.Conns
{
    class Conn
    {
        //常量缓存池大小
        public const int Buff_Size = 1024;
        //客户端连接socket
        public Socket Client_Socket;
        //使用状态
        public bool isUse = false;
        //缓存池
        public byte[] ReadBuff;
        //数据大小
        public int count = 0;
        //构造函数
        public Conn()
        {
            ReadBuff = new byte[Buff_Size];
        }
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="socket"></param>
        public void Init(Socket socket)
        {
            Client_Socket = socket;
            isUse = true;
            count = 0;

        }
        /// <summary>
        /// 缓冲区剩余字节数
        /// </summary>
        /// <returns></returns>
        public int Buff_Remain()
        {
            return Buff_Size - count;
        }
        /// <summary>
        /// 获取客户端地址
        /// </summary>
        /// <returns></returns>
        public string Get_ClientAddress()
        {
            if (!isUse)
            {
                return "无法获取客户端地址";
            }
            return Client_Socket.RemoteEndPoint.ToString();
        }
        /// <summary>
        /// 关闭连接
        /// </summary>
        public void Client_Close()
        {
            if (!isUse)
                return;
            Client_Socket.Close();
            isUse = false;
            Console.WriteLine(Get_ClientAddress() + "断开连接");
        }
    }
}

(2)创建Conn_Helper类管理Conn的使用。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TCP_Sever.Conns
{
    class Conn_Helper
    {
        /// <summary>
        /// 连接池列表
        /// </summary>
        public static Conn[] Conns;
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="coun_size"></param>
        public static void Init(int conns_size)
        {
            if (Conns == null)
            {
                Conns = new Conn[conns_size];
            }
            for (int i = 0; i < conns_size; i++)
            {
                Conns[i] = new Conn();
            }
        }
        /// <summary>
        /// 获取可以使用的连接
        /// </summary>
        /// <returns></returns>
        public static Conn Get_NewConn()
        {
            if (Conns == null)
                return null;
            for (int i = 0; i < Conns.Length; i++)
            {
                if (Conns[i] == null)
                {
                    Conns[i] = new Conn();
                    return Conns[i];
                }
                else if (!Conns[i].isUse)
                {
                    return Conns[i];
                }
            }
            return null;
        }
    }
}


(3)修改Sever类。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using TCP_Sever.Conns;
using TCP_Sever.Timer;
namespace TCP_Sever.Tcpsever
{
    class Sever
    {
        /// <summary>
        /// 服务器套接字
        /// </summary>
        private static Socket sever_socket;
        /// <summary>
        /// 最大连接数
        /// </summary>
        private static int maxConn = 50;
        /// <summary>
        /// 数据缓存池
        /// </summary>
        private static byte[] readBuff = new byte[1024];
        /// <summary>
        /// 开启服务器
        /// </summary>
        /// <param name="host">IP地址</param>
        /// <param name="port">端口号</param>
        public static void Start(string IP, int port)
        {
            //创建服务器套接字
            sever_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //绑定IP和端口号
            IPAddress ip = IPAddress.Parse(IP);
            IPEndPoint point = new IPEndPoint(ip, port);
            sever_socket.Bind(point);
            //监听,0无限制
            sever_socket.Listen(maxConn);
            Conn_Helper.Init(maxConn);
            HeartbeatTime.Start();
            Console.WriteLine("服务器开启成功");
            sever_socket.BeginAccept(AcceptCallBack, null);
        }
        /// <summary>
        /// 同步接收与发送
        /// </summary>
        public static void SynRecv_Send()
        {
            //客户端接入
            if (sever_socket == null)
            {
                Console.WriteLine("请先开启服务器");
                return;
            }
            Socket connfd = sever_socket.Accept();
            Console.WriteLine("客户端接入");
            //获取接收到的流转换为字符串
            int count;
            try
            {
               count= connfd.Receive(readBuff);
            }
            catch (Exception e)
            {
                Console.WriteLine("客户端异常"+e.Message);
                return;
            }
            string str = System.Text.Encoding.UTF8.GetString(readBuff, 0, count);
            Console.WriteLine("收到信息:" + str);
            //获取输入,发送给客户端
            str="服务器接收到消息:"+str;
            byte[] writeBuff = System.Text.Encoding.UTF8.GetBytes(str);
            connfd.Send(writeBuff);
            connfd.Close();
        }
        /// <summary>
        /// Accept回调
        /// </summary>
        /// <param name="ar"></param>
        private static void AcceptCallBack(IAsyncResult ar)
        {
            try
            {
                if (Conn_Helper.Get_NewConn() == null)
                {
                    Console.WriteLine("连接已满");
                }
                else
                {
                    Conn conn = Conn_Helper.Get_NewConn();
                    conn.Init(sever_socket.EndAccept(ar));
                    Console.WriteLine("客户端连接" + conn.Get_ClientAddress());
                    AsynRec(conn);
                }
                sever_socket.BeginAccept(AcceptCallBack, null);
            }
            catch (Exception e)
            {
                Console.WriteLine("AcceptCb失败:" + e.Message);
            }
        }
        /// <summary>
        /// 异步接收
        /// </summary>
        public static void AsynRec(Conn conn)
        {
            //客户端接入
            if (sever_socket == null)
            {
                Console.WriteLine("请先开启服务器");
                return;
            }
            Console.WriteLine("客户端接入");
            //异步接收
            try
            {
                conn.Client_Socket.BeginReceive(conn.ReadBuff, conn.count, conn.Buff_Remain(), SocketFlags.None,AsynReceiveCallBack, conn);
            }
            catch (Exception e)
            {
                Console.WriteLine("客户端异常"+e.Message);
                return;
            }
        }
        /// <summary>
        /// 异步接收回调
        /// </summary>
        /// <param name="ar"></param>
        private static void AsynReceiveCallBack(IAsyncResult ar)
        {
            Conn conn = (Conn)ar.AsyncState;
            lock (conn)
            {
                try
                {
                    conn.count= conn.Client_Socket.EndReceive(ar);
                    string str = System.Text.Encoding.UTF8.GetString(conn.ReadBuff, 0, conn.count);
                    if (str == "HeartTime")
                    {
                        HeartbeatTime.Update_last_HeatTime(conn);
                    }
                    Console.WriteLine("接收到消息:" + str);
                    for (int i = 0; i < Conn_Helper.Conns.Length; i++)
                    { 
                        if (!Conn_Helper.Conns[i].isUse)continue;
                        AsynSend(Conn_Helper.Conns[i]);
                    }
                    //继续接收,实现循环
                    conn.Client_Socket.BeginReceive(readBuff,conn.count ,conn.Buff_Remain(), SocketFlags.None, AsynReceiveCallBack, conn);
                }
                catch (Exception e)
                {
                    Console.WriteLine("客户端断开:" + e.Message);
                }
            }
           
        }
        /// <summary>
        /// 异步发送
        /// </summary>
        public static void AsynSend(Conn conn)
        {
            //客户端接入
            if (sever_socket == null)
            {
                Console.WriteLine("请先开启服务器");
                return;
            }
            byte[] writerBuff = System.Text.Encoding.UTF8.GetBytes("客户端你好"+conn.Get_ClientAddress());
            try
            {   
                //异步发送
                conn.Client_Socket.BeginSend(writerBuff, 0, writerBuff.Length, SocketFlags.None, null, null);
            }
            catch (Exception e)
            {
                Console.WriteLine("发送消息失败" + e.Message);
            }
        }
    }

}

(4)修改Program.cs。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TCP_Sever.Tcpsever;

namespace TCP_Sever
{
    class Program
    {
        static void Main(string[] args)
        {
            Sever.Start("127.0.0.1", 6688);
            while (true)
            {
                //同步
                //Sever.SynRecv_Send();
                //异步
               // Sever.AsynRec();
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_25542475/article/details/86790203