利用Socket来进行Unity间通信

https://blog.csdn.net/MikuLingSSS/article/details/82317768

https://blog.csdn.net/MikuLingSSS/article/details/82357104

里面会用到一些东西,请先读完这两篇博客 使用版本VS-2017(请看完在说我为什么没有提及Unity版本)

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

    首先,我们需要了解一些东西,以下,我会尽可能的用一些简单的语句来描述我的一些理解

    假设,我们住在一个小区,现在我们想要找到一个人,但是我们没有他的地址,只知道他的姓名,这个时候我们应该怎么办?答案肯定不会是一家家的问,找管理员肯定是最简单快捷的方式,毕竟管理者有着小区所有住户的信息......那么管理者就是一个服务器,他会存储目前的所有已经住在小区中人员的信息(偷渡不管),当需要告诉所有住户(比如世界语音,坐标,状态等)的时候,或是小区发生什么事情(重启服务器)的时候,肯定要经过他,也是通过他来通知我们这些住户。

    现在,你也想住在这个小区,那么,我们第一时间肯定是找个房子,这个时候你去找管理者,他会告诉你现在小区还有没有多余的房子,如果没有多余的房子,那么只能与各位住户协商,看看谁有没有搬出去的心(注:服务器的最大连接数目,是否进入等待队列,),而如果有多余的房子,那么我们就可以通过管理员来进行登记姓名,门牌号之类的(注:IP和端口)个人信息。

    在想一下,一个小区辣么大,一个管理员肯定是不够的吧,我们一部分管理者,每个管理者负责一片区域(不同场景中的数据处理),但是一片区域每天发生的事情也不少啊,那么我们在招一些,负责管理区域中的某一部分(地图分割),这样我们的逻辑就比较完善了。

     那么,我们可以得知了

     管理部门=>总的管理者,下发任务的总服务器,区域管理者=>管理地图相关数据传输的逻辑划分,楼层管理者=>管理区域中相应范围内的数据,用户=>连接到我这个服务器的相关连接

     经过上面的说明,我们大概对网络大致了解了一些,其实归根结底就是一个中转+处理(服务器),和发送数据接受数据(客户端)。

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

    打开VS,新建一个Win32控制台应用,加入相关命名空间

using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.Text;

 

    新建一个类,里面声明一些初始变量

namespace SimpleSocket
{
    class Server
    {
        static void Main(string[] args)
        {
           
            Console.ReadLine();
        }
    }
    public class ServerSide
    {
        private Dictionary<int, Client> SaveClientConn;//用来保存Client
        private int clientID;                          // 用来给客户端加上标识
        private Thread listenClientConn;               //监听连接进来客户端的线程
        private Socket server;                         // 这个就是我们的主要服务器 
        private IPAddress ipAddress;                   // Ip
        private static ServerSide Instance;
    }
}

   现在,我们在创建一个委托,广播信息的时候会用到

  class DeleEvent
    {
        public delegate void dele(string info);
        public static dele sendMessage;
               
        public static void AddEvent(dele e)
        {
            sendMessage += e;
        }
    }

 

    这段代码比较简单,如果有不明白的请看最上面的两篇博客;

    现在,开始写一些初始化代码

public static void Initial(string ip, int port)
{
    Instance = new ServerSide(ip, port);            // 单例的初始化
}

private ServerSide(string ip, int port)
{
    DeleEvent.sendMessage += Write;                 // 把广播加入到委托中
    SaveClientConn = new Dictionary<int, Client>(); //
    clientID = 0;                                   // 最开始的clientID
    ipAddress = IPAddress.Parse(ip);                // 把字符转化为IP
    server = new Socket(                            // 初始化Socket
         AddressFamily.InterNetwork,                // 使用Ipv4
         SocketType.Stream,                         // 流式网络
         ProtocolType.Tcp);                         // TCP
    /* UDP
    server = new Socket(
         AddressFamily.InterNetwork,
         SocketType.Dgram,
         ProtocolType.Udp);
    */
    server.Bind(new IPEndPoint(ipAddress, port));   // 绑定IP和端口
    server.Listen(10);                              // 最大连接数目
    listenClientConn = new Thread(ListenConn);      // 创建一个监听链接的线程
    listenClientConn.IsBackground = true;           // 设为后台线程
    listenClientConn.Start();                       // 开启线程
}

private void ListenConn()
{
    while (true)
    {
        Socket client = server.Accept();            // 如果有相应的Client连接,则创建一个Socket
        Client c = new Client(client, clientID);    // 这个类在后面
        SaveClientConn.Add(clientID, c);            // 把这个连接保存起来
        clientID++;                                 // 客户端标识加一
    }
}

private void Write(string clientMes)
{
     Console.WriteLine(clientMes);
}

 

我们现在已经绑定了服务器的IP和端口,并开启了监听,接下来,进行处理连接进来的客户端

class Client
{
    private Socket client;                      // 客户端的Socket连接
    private int clientID;                       // 字典的ID 也是这个客户端的ID
    private Thread receive;                     // 接受客户端传输过来数据的线程
    private byte[] result = new byte[1024];     // 需要接受数据的缓冲区
    public Client(Socket client, int clientID)
    {
        DeleEvent.AddEvent(SendMessage);        // 把发送方法保存如Delegate中
        this.client = client;                   // 下面方法和服务器类似 不在解释   
        this.clientID = clientID;
        receive = new Thread(ReceiveMessage);
        receive.IsBackground = true;
        receive.Start();
    }
    private void ReceiveMessage()
    {
        while (true)
        {
            try
            {
                int length = client.Receive(result);   // 接受数据的长度,如果没有数据传输进来下面不会执行
                Console.WriteLine("Client-{0}:{1}", clientID, Encoding.UTF8.GetString(result, 0, length));           // 输出客户端传送过来的消息和客户端ID

                // 这个地方之所以要先减去,试音为我们上面已经在客户端已经说过了一句话,不应该再把我们说的话传给我们,而应该是只传给服务器和其他的客户端
                DeleEvent.sendMessage -= SendMessage;
                // 广播,发送给其他客户端
                DeleEvent.sendMessage(client + ":" + Encoding.UTF8.GetString(result, 0, length));
                DeleEvent.sendMessage += SendMessage;

                // 这是服务器给他回传的话语 QAQ
                SendMessage("Server:我知道了,你可以闭嘴了");
            }
            catch (Exception ex)
            {
                // 如果我们的客户端关闭连接 这个方法会报错 所以用Try 
                Console.WriteLine("Client-{0}关闭连接:Info-{1}", clientID, ex.Message);
                // 销毁相应对象
                client.Shutdown(SocketShutdown.Both);
                DeleEvent.sendMessage -= SendMessage; 
                client.Close();
                receive.Abort();
                break;
            }
        }
    }
    private void SendMessage(string info)
    {
        client.Send(Encoding.UTF8.GetBytes(info));
    }
}

以上,服务器就搭建完成了,运行的时候只需要

class Server
{
   static void Main(string[] args)
   {
        ServerSide.Initial("127.0.0.1", 9002);
        Console.ReadLine();
   }
}

这就可以了,不过服务器没办法主动发送信息给客户端(友情提示:委托)

================================================================================================ 客户端

 

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

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            ReceiveEvent.Instance.AddEvent(cw);
            ConnServer.Initial("127.0.0.1", 9002);
            ConnServer.Instance.Conn();

            while (true)
            {
                string str = Console.ReadLine();
                ConnServer.Instance.SendMessage(str);      // 发送消息给服务器
            }
        }
        static void cw(string n)
        {
            Console.WriteLine(n);
        }
    }

    /// <summary>
    /// 连接服务器  由于代码和服务器类似 这里不做注解
    /// </summary>
    public class ConnServer
    {
        public static ConnServer Instance;
        private Socket client;
        private string ip;
        private int port;
        private IPAddress ipaddress;
        private byte[] result = new byte[1024];
        /// <summary>
        /// 初始化参数
        /// </summary>
        private ConnServer(string ip, int port)
        {
            this.ip = ip;
            this.port = port;
            ipaddress = IPAddress.Parse(ip);
            client = new Socket(
                AddressFamily.InterNetwork,
                SocketType.Stream,
                ProtocolType.Tcp);
        }
        /// <summary>
        /// 连接服务器
        /// </summary>
        public void Conn()
        {
            if (!client.Connected)
            {
                client.Connect(new IPEndPoint(ipaddress, port));
                Thread startReceive = new Thread(ReceiveMessage);
                startReceive.IsBackground = true;
                startReceive.Start();
            }
        }
        /// <summary>
        /// 接收来自服务器的信息
        /// </summary>
        public void ReceiveMessage()
        {
            while (true)
            {
                int mesLength = client.Receive(result);
                // 如果我这个客户端接受到了消息 则利用委托执行某个方法
                // 我这里的方法比较简单 但是你可以进行一些处理 
                // 比如根据传入的数据 解析之后进行某些操作之类的
                ReceiveEvent.Instance.play(Encoding.UTF8.GetString(result, 0, mesLength));
            }
        }
        /// <summary>
        /// 向服务器发送信息
        /// </summary>
        public void SendMessage(string info)
        {
            client.Send(Encoding.UTF8.GetBytes(info));
        }
        /// <summary>
        /// 初始化参数
        /// </summary>
        public static void Initial(string ip, int port)
        {
            Instance = new ConnServer(ip, port);
        }
    }

    /// <summary>
    /// 添加事件,有信息传入可直接调取方法
    /// </summary>
    public class ReceiveEvent
    {
        private static ReceiveEvent instance;
        public static ReceiveEvent Instance
        {
            get
            {
                if (instance == null)
                    instance = new ReceiveEvent();
                return instance;
            }
        }
        public delegate void Del(string info);
        private Del Receive;
        /// <summary>
        /// 添加一个方法到委托中
        /// </summary>
        public void AddEvent(Del e)
        {
            Receive += e;
        }
        /// <summary>
        /// 执行委托中的事件
        /// </summary>
        public void play(string info)
        {
            Receive(info);
        }
    }

}

 

    如果看了前两篇博客还是不太明白这个和Unity有什么关系的话.......

    => https://blog.csdn.net/MikuLingSSS/article/details/82459555

GitHub : https://github.com/MLMikuLing/Socket-18-09-05

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值