unity3d Socket异步连接(附带一个案例)

socket 同步

同步就是有阻塞,比如接收数据时如果没有数据就等待,等到有数据了再执行下一步代码。

socket 异步
异步就不用等待,比如指定接收数据后就会继续执行一下步代码,等到有数据了再跳出当前执行的代码转去执行异步调用。
同步的话通常要配合多线程(否则在阻塞的时候当前线程会停止,如果当前线程是UI线程就表现出好像界面停止的样子)。

服务器储存客户集合 客户类(服务器的)

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

namespace 飞机服务器
{
    class Client
    {
        public Socket socket;
        public byte[] data = new byte[1024];
        public string ip;
        public string nick;
    }
}

服务器

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

namespace 飞机服务器
{
    class NetManager:Singleton<NetManager>
    {
        Socket socket;
        public List<Client> clients = new List<Client>();
        public void Init()
        {
            socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            IPEndPoint ip = new IPEndPoint(IPAddress.Any, 8585);
            socket.Bind(ip);
            socket.Listen(100);
            Debug.Log("服务器开启");
            socket.BeginAccept(OnAccept, null);//异步连接
        }

        private void OnAccept(IAsyncResult ar)
        {
            Socket client = socket.EndAccept(ar);//异步接受传入的连接尝试
            IPEndPoint iP = client.RemoteEndPoint as IPEndPoint;
            Debug.Log(iP.Address+":"+iP.Port+"连接");//获取连接者的IP地址
            Client cli = new Client();
            cli.socket = client;
            cli.ip = iP.Port.ToString();
            clients.Add(cli);
            cli.socket.BeginReceive(cli.data, 0, cli.data.Length, SocketFlags.None, OnRecive, cli);
            socket.BeginAccept(OnAccept, null);
        }

        private void OnRecive(IAsyncResult ar)
        {
            Client cli = ar.AsyncState as Client;
            int len = cli.socket.EndReceive(ar);//获取接收消息长度
            if(len>0)
            {
                //创建一个正好长度的数组接收
                byte[] datar = new byte[len];
                Buffer.BlockCopy(cli.data, 0, datar,0, len);
                //把完整消息拆分成消息头和消息体
                //消息头 = id
                int id = BitConverter.ToInt32(datar, 0);
                byte[] boby = new byte[datar.Length - 4];//创建一个接收消息体的byte数组
                //消息体等于消息内容
                Buffer.BlockCopy(datar, 4, boby, 0, boby.Length);
                //消息分发
                //通过消息id将消息内容给对应的回调函数;
                MessageCenter.Ins().BroadCast(id, boby, cli);
                //异步接收消息
                cli.socket.BeginReceive(cli.data, 0, cli.data.Length, SocketFlags.None, OnRecive, cli);
            }
            else
            {
                cli.socket.Shutdown(SocketShutdown.Both);//禁止消息的发送和接收
                cli.socket.Close();//关闭连接并释放所有相关资源
                clients.Remove(cli);//从客户端集合中移除
                Debug.Log(cli.ip+"离线");
            }
           // throw new NotImplementedException();
        }
        public void Send(int id,string str,Client cli)
        {
            //消息头
            byte[] head = BitConverter.GetBytes(id);//转换为byte
            //消息体
            byte[] body = UTF8Encoding.UTF8.GetBytes(str);
            //完整消息=消息头+消息体
            byte[] data = new byte[head.Length+body.Length];
            Buffer.BlockCopy(head,0,data,0,head.Length);
            Buffer.BlockCopy(body, 0, data, 4, body.Length);
            cli.socket.BeginSend(data, 0, data.Length, SocketFlags.None, OnSend, cli);
        }
        public void Send(int id, byte[] str)
        {
            //消息头
            byte[] head = BitConverter.GetBytes(id);//转换为byte
            //消息体
          
            //完整消息=消息头+消息体
            byte[] data = new byte[head.Length + str.Length];
            Buffer.BlockCopy(head, 0, data, 0, head.Length);
            Buffer.BlockCopy(str, 0, data, 4, str.Length);
            foreach (var item in clients)
            {
                item.socket.BeginSend(data, 0, data.Length, SocketFlags.None, OnSend, item);
            }
          
        }

        private void OnSend(IAsyncResult ar)
        {
            Client cli = ar.AsyncState as Client;
            int len = cli.socket.EndSend(ar);//结束挂起发送
            Debug.Log("发送长度"+len);
           // throw new NotImplementedException();
        }
    }
   
}

消息中心

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

namespace 飞机服务器
{
    /// <summary>
    /// 消息中心
    /// </summary>
    class MessageCenter:Singleton<MessageCenter>
    {
        Dictionary<int, Action<object>> dic = new Dictionary<int, Action<object>>();
        //注册
        public void AddListener(int id,Action<object> action)
        {
           if(dic.ContainsKey(id))
            {
                dic[id] += action;
            }
           else
            {
                dic.Add(id, action);
            }
        }
        //发送
        public void BroadCast(int id,params object[] data)
        {
            if(dic.ContainsKey(id))
            {
                dic[id](data);
            }
        }
        //移除
        public void Remove(int id,Action<object> action)
        {
            if(dic.ContainsKey(id))
            {
                dic[id] -= action;
                if(dic[id]==null)
                {
                    dic.Remove(id);
                }
            }
        }
    }
}

注册事件

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

namespace 飞机服务器
{
    static class MsgID
    {
       // public const int S2C_SETCOLOR = 1001;//服务器向客户端发颜色
        public const int S2C_CHAT = 1001;//服务器向客户端发聊天信息
        public const int C2S_CHAT = 1002;//客户端向服务器发聊天信息
        public const int C2S_NICK = 1003;
        public const int S2C_NICK = 1004;
        public const int C2S_ANGLEZ = 1005;
        public const int S2C_ANGLEZ = 1006;
        public const int C2S_ANGLEX = 1007;
        public const int S2C_ANGLEX = 1008;
    }
    class Chat:Singleton<Chat>
    {
       public void Init()
        {
          
            MessageCenter.Ins().AddListener(MsgID.C2S_CHAT, OnChat);
            MessageCenter.Ins().AddListener(MsgID.C2S_NICK, OnStart);
            MessageCenter.Ins().AddListener(MsgID.C2S_ANGLEZ, OnAngleZ);
            MessageCenter.Ins().AddListener(MsgID.C2S_ANGLEX, OnAngleX);
        }

        private void OnAngleX(object obj)
        {
            
        }

        private void OnAngleZ(object obj)
        {
          
        }
        private void OnStart(object obj)
        {
          
        }

        private void OnChat(object obj)
        {
           
        }
    }
}

下面有一个案例当然尽管案例可能不太完美

案例

YZXXDXN/异步平面: 异步连接 (github.com)

猜你喜欢

转载自blog.csdn.net/qq_57896821/article/details/121938413
今日推荐