Unity通信之Socket架构的业务层使用方法

效果:两个客户端,一个称为客户端A,一个称为客户端B。

        一个服务器。

一组协议。

客户端A发送,服务器接受到,并且转发给所有客户端。

客户端A和客户端B接收到服务器的消息转发,并且读取出来,显示到客户端A和客户端B。

1.网络层定义好DTO以及协议。

 

2. 客户端的chatcontroller可以去拿服务端的DTO以及调api发送DTO给服务端。

 

3.服务端的controller要接受DTO并且转发。

 

4.在客户端和服务端的controllermanager里面都要注册刚才的请求。

客户端:

 

服务端:

 

代码:

客户端:

 

IBaseController.cs:

using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


public interface IBaseController
{
    void GetData(RequestType type, object data);
}

ChatController.cs

using System.Collections;
using System.Collections.Generic;
using Common;
using UnityEngine;
public class ChatController : IBaseController
{
    public static ChatController instance = new ChatController();
    public void GetData(RequestType type, object data)
    {
        if (type == RequestType.Chat)
        {
            var dto = (data as ChatDTO);

            Debug.LogError("["+dto.userID+"]:"+dto.chatMsg);
        }
    }
    public void chat(string text)
    {
        var dto = new ChatDTO();
        dto.chatMsg = text;
        dto.userID = GameModel.instance.UserID;
        ClientManager.instance.SendRequest(RequestType.Chat, dto);
    }
}

ChatView.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


public class ChatView : MonoBehaviour {

	void Start () {
		
	}
	
	void Update () {
        

    }
    public void chat()
    {
      ChatController.instance.chat(transform.Find("InputField").GetComponent<InputField>().text);
    }

}

ClientManager.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System;
using Common;

/// <summary>
/// 管理服务器端的Socket
/// </summary>
public class ClientManager : MonoBehaviour
{

    public static ClientManager instance;
    private const string IP = "127.0.0.1";
    private const int PORT = 6688;

    private Socket socket;
    private Message msg = new Message();

    private Dictionary<object, RequestType> delayRequest = new Dictionary<object, RequestType>();
    public void Awake()
    {
        instance = this;

        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            socket.Connect(IP, PORT);
            StartReceive();
            Debug.LogError("链接成功!");
            //socket准备完毕,发送登录请求
            GameModel.instance.Init();
        }
        catch (Exception e)
        {
            Debug.LogError("无法连接到服务器端,请检查您的网络!!" + e);
        }
    }
    private void StartReceive()
    {
        socket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveDataCallback, null);
    }
    private void ReceiveDataCallback(IAsyncResult ar)
    {
        try
        {
            if (socket == null || socket.Connected == false) return;
            int count = socket.EndReceive(ar);

            msg.RecieveData(count, HandleController);

            StartReceive();
        }
        catch (Exception e)
        {
            Debug.Log(e);
        }
    }
    private void HandleController(RequestType t, object data)
    {
        //找到对应的respone
        lock (delayRequest)
        {
            delayRequest.Add(data, t);
        }
    }

    private void FixedUpdate()
    {
        lock (delayRequest)
        {
            if (delayRequest.Count > 0)
            {
                foreach (var item in delayRequest)
                {
                    ControllerManager.instance.HandleController(item.Value, item.Key);
                }
                delayRequest.Clear();
            }
        }
    }

    public static void SendMesage(string msg)
    {
        var dto = new BaseDTO();
        dto.data = msg;
        ClientManager.instance.SendRequest(RequestType.None, dto);
    }
    public void SendRequest(RequestType type, object data)
    {
        byte[] bytes = Message.WriteData(type, data);
        socket.Send(bytes);
    }

    public void OnDestroy()
    {
        try
        {
            socket.Close();
        }
        catch (Exception e)
        {
            Debug.LogError("无法连接!!" + e);
        }
    }
}

Message.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using Common;
using System.Text;
using System.Linq;
public class Message  {

    private byte[] data = new byte[1024];
    private int startIndex = 0;//我们存取了多少个字节的数据在数组里面

    //public void AddCount(int count)
    //{
    //    startIndex += count;
    //}
    public byte[] Data
    {
        get { return data; }
    }
    public int StartIndex
    {
        get { return startIndex; }
    }
    public int RemainSize
    {
        get { return data.Length - startIndex; }
    }
    /// <summary>
    /// 解析数据
    /// </summary>
    public void RecieveData(int newDataAmount, Action<RequestType, object> processDataCallback)
    {
        startIndex += newDataAmount;
        while (true)
        {
            if (startIndex <= 4) return;
            int count = BitConverter.ToInt32(data, 0);
            //接收指定长度数据
            if ((startIndex - 4) >= count)
            {
                //获取协议码
                RequestType actionCode = (RequestType)BitConverter.ToInt32(data, 4);

                //找到对应request
                processDataCallback(actionCode, SerializeHelper.DeserializeWithBinary(data.Skip(8).ToArray()));
                Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
                startIndex -= (count + 4);
            }
            else
            {
                break;
            }
        }
    }
    /// <summary>
    /// 打包数据
    /// </summary>
    /// <param name="actionCode"></param>
    /// <param name="dto"></param>
    /// <returns></returns>
    public static byte[] WriteData(RequestType actionCode, object dto)
    {
        //获取协议码
        byte[] actionCodeBytes = BitConverter.GetBytes((int)actionCode);
        //转换成二进制
        byte[] dataBytes = SerializeHelper.SerializeToBinary(dto);
        int dataAmount = dataBytes.Length + actionCodeBytes.Length;
        //封包(头+协议码+内容)
        byte[] dataAmountBytes = BitConverter.GetBytes(dataAmount);
        //byte[] newBytes = dataAmountBytes.Concat(requestCodeBytes).ToArray<byte>();//Concat(dataBytes);
        //return newBytes.Concat(dataBytes).ToArray<byte>();
        return dataAmountBytes.Concat(actionCodeBytes).ToArray<byte>()
            .Concat(dataBytes).ToArray<byte>();
    }

}

ControllerManager.cs:

using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

public class ControllerManager
{
    public static ControllerManager instance = new ControllerManager();
    public Dictionary<RequestType, IBaseController> ControllerDic = new Dictionary<Common.RequestType, IBaseController>();
    public void HandleController(RequestType type, object data)
    {
        ControllerDic[type].GetData( type, data );
    }
    private ControllerManager()
    {
        ControllerDic.Add(RequestType.None,new GameController());
        ControllerDic.Add(RequestType.Login,new LoginController());
        ControllerDic.Add(RequestType.Chat,ChatController.instance);
    }
}

GameController.cs:

using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

public class GameController : IBaseController
{
    public void GetData(RequestType type, object dto)
    {
        if (type == RequestType.None)
        {
           
                Debug.LogError("收到服务器消息:"+ (dto as BaseDTO).data);
            
        }
    }

}

GameModel.cs:

using Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


public class GameModel
{
    public static GameModel instance = new GameModel();
    public int UserID;
    public void Init()
    {
        ClientManager.instance.SendRequest(Common.RequestType.Login,new Common.LoginDTO());
    }
}

SerializeHelper.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;

public static class SerializeHelper
{
    /// <summary>
    /// 使用UTF8编码将byte数组转成字符串
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static string ConvertToString(byte[] data)
    {
        return Encoding.UTF8.GetString(data, 0, data.Length);
    }

    /// <summary>
    /// 使用指定字符编码将byte数组转成字符串
    /// </summary>
    /// <param name="data"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static string ConvertToString(byte[] data, Encoding encoding)
    {
        return encoding.GetString(data, 0, data.Length);
    }

    /// <summary>
    /// 使用UTF8编码将字符串转成byte数组
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static byte[] ConvertToByte(string str)
    {
        return Encoding.UTF8.GetBytes(str);
    }

    /// <summary>
    /// 使用指定字符编码将字符串转成byte数组
    /// </summary>
    /// <param name="str"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static byte[] ConvertToByte(string str, Encoding encoding)
    {
        return encoding.GetBytes(str);
    }

    /// <summary>
    /// 将对象序列化为二进制数据 
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeToBinary(object obj)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, obj);

        byte[] data = stream.ToArray();
        stream.Close();

        return data;
    }

    /// <summary>
    /// 将对象序列化为XML数据
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeToXml(object obj)
    {
        MemoryStream stream = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(obj.GetType());
        xs.Serialize(stream, obj);

        byte[] data = stream.ToArray();
        stream.Close();

        return data;
    }

    /// <summary>
    /// 将二进制数据反序列化
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static object DeserializeWithBinary(byte[] data)
    {
        MemoryStream stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        BinaryFormatter bf = new BinaryFormatter();
        object obj = bf.Deserialize(stream);

        stream.Close();

        return obj;
    }

    /// <summary>
    /// 将二进制数据反序列化为指定类型对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    public static T DeserializeWithBinary<T>(byte[] data)
    {
        return (T)DeserializeWithBinary(data);
    }

    /// <summary>
    /// 将XML数据反序列化为指定类型对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    public static T DeserializeWithXml<T>(byte[] data)
    {
        MemoryStream stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        XmlSerializer xs = new XmlSerializer(typeof(T));
        object obj = xs.Deserialize(stream);

        stream.Close();

        return (T)obj;
    }
}

=========================================================================

服务器:

 

ChatDTO.cs:

using System;
using System.Collections.Generic;
using System.Text;

namespace Common
{
    [Serializable]
    public class ChatDTO
    {
        public int userID;
        public string chatMsg;
    }
}

DTO.cs:

using System;
using System.Collections.Generic;
using System.Text;
namespace Common
{
    [Serializable]
    public class BaseDTO
    {
        public string data;
    }

}

ServerType.cs:

using System;
using System.Collections.Generic;
using System.Text;

namespace Common
{
    //协议类型
    public enum RequestType
    {
        None,
        Login,
        Chat,
    }
}

SerializeHelper.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml.Serialization;

public static class SerializeHelper
{
    /// <summary>
    /// 使用UTF8编码将byte数组转成字符串
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static string ConvertToString(byte[] data)
    {
        return Encoding.UTF8.GetString(data, 0, data.Length);
    }

    /// <summary>
    /// 使用指定字符编码将byte数组转成字符串
    /// </summary>
    /// <param name="data"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static string ConvertToString(byte[] data, Encoding encoding)
    {
        return encoding.GetString(data, 0, data.Length);
    }

    /// <summary>
    /// 使用UTF8编码将字符串转成byte数组
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public static byte[] ConvertToByte(string str)
    {
        return Encoding.UTF8.GetBytes(str);
    }

    /// <summary>
    /// 使用指定字符编码将字符串转成byte数组
    /// </summary>
    /// <param name="str"></param>
    /// <param name="encoding"></param>
    /// <returns></returns>
    public static byte[] ConvertToByte(string str, Encoding encoding)
    {
        return encoding.GetBytes(str);
    }

    /// <summary>
    /// 将对象序列化为二进制数据 
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeToBinary(object obj)
    {
        MemoryStream stream = new MemoryStream();
        BinaryFormatter bf = new BinaryFormatter();
        bf.Serialize(stream, obj);

        byte[] data = stream.ToArray();
        stream.Close();

        return data;
    }

    /// <summary>
    /// 将对象序列化为XML数据
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    public static byte[] SerializeToXml(object obj)
    {
        MemoryStream stream = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(obj.GetType());
        xs.Serialize(stream, obj);

        byte[] data = stream.ToArray();
        stream.Close();

        return data;
    }

    /// <summary>
    /// 将二进制数据反序列化
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static object DeserializeWithBinary(byte[] data)
    {
        MemoryStream stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        BinaryFormatter bf = new BinaryFormatter();
        object obj = bf.Deserialize(stream);

        stream.Close();

        return obj;
    }

    /// <summary>
    /// 将二进制数据反序列化为指定类型对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    public static T DeserializeWithBinary<T>(byte[] data)
    {
        return (T)DeserializeWithBinary(data);
    }

    /// <summary>
    /// 将XML数据反序列化为指定类型对象
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="data"></param>
    /// <returns></returns>
    public static T DeserializeWithXml<T>(byte[] data)
    {
        MemoryStream stream = new MemoryStream();
        stream.Write(data, 0, data.Length);
        stream.Position = 0;
        XmlSerializer xs = new XmlSerializer(typeof(T));
        object obj = xs.Deserialize(stream);

        stream.Close();

        return (T)obj;
    }
}

ChatController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Servers;

namespace GameServer.Server.Contrller
{
    public class ChatController : IBaseController
    {
        public void GetData(RequestType type, object data, Client client)
        {
            //传入数据
            var dto = data as ChatDTO;
            //转发数据
            client.SendDataToAll(type,dto);
        }
    }
}

ControllerManager.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Server.Contrller;
using GameServer.Servers;
namespace GameServer.Servers
{
    class ControllerManager
    {
        public static ControllerManager instance = new ControllerManager();
        public Dictionary<RequestType, IBaseController> ControllerDic = new Dictionary<Common.RequestType, IBaseController>();
        public void HandleController(RequestType type, object data, Client client)
        {
            ControllerDic[type].GetData( type, data, client);
        }
        private ControllerManager()
        {
            Console.WriteLine("开始注册crl");
            ControllerDic.Add(RequestType.None, new GameController());
            ControllerDic.Add(RequestType.Login, new LoginController());
            ControllerDic.Add(RequestType.Chat, new ChatController());
        }
    }
}

GameController.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Common;
using GameServer.Servers;

namespace GameServer.Server.Contrller
{
    class GameController : IBaseController
    {
        public void GetData(RequestType type, object data, Client client)
        {
            Console.WriteLine("ww");
            if (type == RequestType.None)
            {
                var dto = data as BaseDTO;
                client.SendMessage("服务端收到消息:"+ dto.data);
            }
        }

    }
}

IBaseController.cs:

using Common;
using GameServer.Servers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GameServer.Server.Contrller
{
    interface IBaseController
    {
        void GetData( RequestType type, object data, Client client);
    }
}

Client.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using Common;
using MySql.Data.MySqlClient;

namespace GameServer.Servers
{
    public class Client
    {
        public int ID;
        private Socket socket;
        private Server server;
        private Message msg = new Message();

        //初始化客户端
        public Client(Socket socket,Server server)
        {
            this.socket = socket;
            this.server = server;
        }
        //开始接收消息
        public void BeginReceive()
        {
            if (socket == null || socket.Connected == false) return;
            socket.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, ReceiveDataCallback, null);

            SendMessage("已连接");
        }
        //收到消息
        private void ReceiveDataCallback(IAsyncResult ar)
        {
            try
            {
                if (socket == null || socket.Connected == false) return;
                int count = socket.EndReceive(ar);
                if (count == 0)
                {
                    Close();
                }
                msg.RecieveData(count,HandleController);
                BeginReceive();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                Close();
            }
        }
        //找到对应的Contrller
        private void HandleController( RequestType type,object data)
        {
            ControllerManager.instance.HandleController(type, data, this);
        }
        //关闭
        private void Close()
        {
            if (socket != null)
                socket.Close();

            server.RemoveClient(this);
        }
        //发送数据
        public void SendData(RequestType type, object data)
        {
            try
            {
                byte[] bytes = Message.WriteData(type, data);
                socket.Send(bytes);
            }
            catch (Exception e)
            {
                Console.WriteLine("无法发送消息:" + e);
            }
        }
        //给所有客户端发送数据
        public void SendDataToAll(RequestType type, object data)
        {
            try
            {
                byte[] bytes = Message.WriteData(type, data);
                foreach (var item in server.clientDic)
                {
                    item.Value.SendData(type, data);
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("无法发送消息:" + e);
            }
        }

        //直接发送字符串
        public void SendMessage(string msg)
        {
            var dto = new BaseDTO();
            dto.data = msg;
            SendData(RequestType.None, dto);
        }
    }
}

Message.cs:

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

namespace GameServer.Servers
{
    class Message
    {
        private byte[] data = new byte[1024];
        private int startIndex = 0;//我们存取了多少个字节的数据在数组里面

        public byte[] Data
        {
            get { return data; }
        }
        public int StartIndex
        {
            get { return startIndex; }
        }
        public int RemainSize
        {
            get { return data.Length - startIndex; }
        }
        /// <summary>
        /// 解析数据,解包
        /// </summary>
        public void RecieveData(int amout, Action<RequestType, object> processDataCallback )
        {
            startIndex += amout;
            while (true)
            {
                if (startIndex <= 4) return;
                int count = BitConverter.ToInt32(data, 0);
                if ((startIndex - 4) >= count)
                {
                  
                    RequestType actionCode = (RequestType)BitConverter.ToInt32(data, 4);
                    //string s = Encoding.UTF8.GetString(data, 12, count-8);
                    Console.WriteLine(actionCode);
                    processDataCallback(actionCode, SerializeHelper.DeserializeWithBinary(data.Skip(8).ToArray()));
                    Array.Copy(data, count + 4, data, 0, startIndex - 4 - count);
                    startIndex -= (count + 4);
                }
                else
                {
                    break;
                }
            }
        }
        /// <summary>
        /// 打包
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public static byte[] WriteData(RequestType type,object dto)
        {
            byte[] typeBytes = BitConverter.GetBytes((int)type);
            
            byte[] dataBytes =SerializeHelper.SerializeToBinary(dto);
            int dataLength = typeBytes.Length + dataBytes.Length;
            byte[] LengthBytes = BitConverter.GetBytes(dataLength);
            byte[] b =LengthBytes.Concat(typeBytes).ToArray<byte>();
            return b.Concat(dataBytes).ToArray<byte>();
        }
    }
}

Server.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using Common;
namespace GameServer.Servers
{
   public class Server
    {
        private Socket serverSocket;

        public Dictionary<int,Client> clientDic = new Dictionary<int, Client>();

        public Server() {}

        //设置IP和端口,开始侦听客户端
        internal void Start(string ipStr, int port)
        {
            var ipEndPoint = new IPEndPoint(IPAddress.Parse(ipStr), port);

            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocket.Bind(ipEndPoint);
            serverSocket.Listen(0);
            serverSocket.BeginAccept(AcceptClient, null);
            Console.WriteLine("开始侦听客户端");
        }
        //捕获客户端
        private void AcceptClient(IAsyncResult ar  )
        {
            Socket clientSocket = serverSocket.EndAccept(ar);
            Client client = new Client(clientSocket,this);
            client.ID = new Random().Next(0,999999999);
            client.BeginReceive();
            clientDic.Add(client.ID,client);
            serverSocket.BeginAccept(AcceptClient, null);
            Console.WriteLine("有客户端进来啦,分配ID:"+client.ID);
        }
        //移除客户端
        public void RemoveClient(Client client)
        {
            RemoveClient(client.ID);
        }
        //移除客户端
        public void RemoveClient(int clientID)
        {
            lock (clientDic)
            {
                clientDic.Remove(clientID);
            }
            Console.WriteLine("有客户端退出啦,分配ID:" + clientID);
        }
    }
}

Program.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using GameServer.Servers;
namespace 游戏服务器端
{
    class Program
    {
        static void Main(string[] args)
        {
         // var i =   ControllerManager.instance;

            Server server = new Server();
            server.Start("127.0.0.1", 6688);

            Console.ReadKey();
        }
    }
}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值