添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
发财的黄花菜  ·  Django ForeignKey ...·  2 周前    · 
玩滑板的啄木鸟  ·  js ...·  2 月前    · 
帅呆的茴香  ·  PyQ5 - 知乎·  1 年前    · 

Unity实现服务器:1、Socket通信

最近研究了一下Unity的网络框架,踩了很多的坑,所以想在这里写篇文章作为总结,文章只针对实现,不讲过多的原理,后续会陆续更新完整的服务器框架。

要想实现服务器框架,首先就是要使用Socket进行通信,Socket通信大致逻辑:服务端暴露端口号和IP地址,客户端通过访问这个IP地址,进行数据传输,传输的数据为二进制数据。接下来为大家讲讲怎么实现。文章最后放出源码。

需要工具:unity、vs2019

1、首先在服务器端创建服务端脚本Server,我这直接用本地:

大致内容:暴露服务器ip地址、端口号、最大连接数,等待客户端连接后发送给客户端信息,接收客户端发来的信息。

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
    class Program
        private static string _ipAdress = "127.0.0.1";  //ip地址
        private static int _port = 5000;  //端口号
        private static int _maxConnect = 20;  //最大连接数
        private static Socket _serverSocket;
        private static Socket _clientSocket;
        static void Main(string[] args)
            //1、创建一个服务端socket对象
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //2、绑定一个ip和端口
            IPAddress ipaddress = IPAddress.Parse(_ipAdress);//将一个字符串类型的ip地址,转换成一个IPAdress对象
            EndPoint endPoint = new IPEndPoint(ipaddress, _port);
            _serverSocket.Bind(endPoint);//向操作系统申请一个可用的ip和端口号来通讯
            //3、开始监听客户端的连接请求
            _serverSocket.Listen(_maxConnect);//设置最大连接数
            Console.WriteLine(string.Format("开启服务端{0}...", _serverSocket.LocalEndPoint));
            _clientSocket = _serverSocket.Accept();//阻塞当前线程,直到有一个客户端连接服务器
            Console.WriteLine("接受到客户端的连接请求!");
            //4、发送、接收消息
            string message = "hello client";
            byte[] data = Encoding.UTF8.GetBytes(message);//将字符串转成字节数组
            _clientSocket.Send(data);
            Console.WriteLine("服务器向客户端发送了一条消息:" + message);
            //5、接收客户端发来的信息
            byte[] data2 = new byte[1024];//存放消息的字节数容器 1M大小
            int length = _clientSocket.Receive(data2);
            string messgae2 = Encoding.UTF8.GetString(data2, 0, length);//bytes转换成string
            Console.WriteLine("服务器接受到客户端发来的信息" + messgae2);
            Console.ReadLine();

2、创建Unity项目,并添加Client脚本。

using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class Client : MonoBehaviour
    private Socket _tcpClient;
    private string _serverIP = "127.0.0.1";//服务器ip地址
    private int _serverPort = 5000;//端口号
    void Start()
        //1、创建socket
        _tcpClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //2、建立一个连接请求
        IPAddress iPAddress = IPAddress.Parse(_serverIP);
        EndPoint endPoint = new IPEndPoint(iPAddress, _serverPort);
        _tcpClient.Connect(endPoint);
        Debug.Log("请求服务器连接");
        //3、接受、发送消息
        byte[] data = new byte[1024];
        int length = _tcpClient.Receive(data);
        var message = Encoding.UTF8.GetString(data, 0, length);
        Debug.Log("客户端收到来自服务器发来的信息" + message);
        //发送消息
        string message2 = "Client Say To Hello";
        _tcpClient.Send(Encoding.UTF8.GetBytes(message2));
        Debug.Log("客户端向服务器发送消息" + message2);
}

3、开启服务器

4、开启客户端

将写好的脚本挂载在场景中

5、效果

服务端效果
客户端效果

最基本的通信已经实现,现在来开始重构一下代码。

服务器端:

将Client封装成一个类,要有初始化、开始接收、接收回调等方法

将Server封装成一个类,要有启动服务器,关闭服务器、接收信息等方法,并且还要有管理Client的方法。

客户端:

将Client封装成一个类,包括初始化、开始接收、接收回调等方法。

接下来实现:

服务器端:Server类

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
    class Server
        private Socket _serverSocket;
        private int _prot;
        private int _maxClient;
        private string ipAdress;
        public List<Client> ClientList = new List<Client>();//客户端列表
        public Server(string ipAdress, int prot, int maxClient)
            this.ipAdress = ipAdress;
            this._prot = prot;
            this._maxClient = maxClient;
            Start();//启动
        //启动服务器
        public void Start()
                //1、创建一个socket对象
                _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                //2、绑定一个ip和端口
                IPAddress ipaddress = IPAddress.Parse(ipAdress);//将一个字符串类型的ip地址,转换成一个IPAdress对象
                EndPoint endPoint = new IPEndPoint(ipaddress, _prot);
                _serverSocket.Bind(endPoint);//向操作系统申请一个可用的ip和端口号来通讯
                _serverSocket.Listen(_maxClient);//设置最大连接数
                Console.WriteLine(string.Format("开启服务端{0}...", _serverSocket.LocalEndPoint));
                StartAccept();
            catch (Exception)//出现异常则关闭服务器
                //Close();
                throw;
        //开始接收信息
        private void StartAccept()
            OnAccept();
        //接收信息中
        private void OnAccept()
            while (true)
                Socket clientSocket = _serverSocket.Accept();
                Console.WriteLine(string.Format("客户端 {0} 连接", clientSocket.RemoteEndPoint));
                Client client = new Client(clientSocket);
                client.OnSend(Encoding.Default.GetBytes("登录成功"));
        //关闭所有服务器
        public void Close()
            foreach (var client in ClientList)
                client.Close();
            _serverSocket.Close();
}

Client类:

using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Server
    class Client
        private Thread _recvThread;
        public Socket clientSocket;
        public Client(Socket socket)
            clientSocket = socket;
            StartRecv();
        //开始接收
        private void StartRecv()
            _recvThread = new Thread(OnRecv);
            _recvThread.IsBackground = true;
            _recvThread.Start();
        //接收中
        private void OnRecv()
                while (true)
                    byte[] buff = new byte[1024];
                    clientSocket.Receive(buff);
                    Console.WriteLine(Encoding.Default.GetString(buff));
            catch (Exception)
                Close();
                throw;
        //发送信息
        public void OnSend(byte[] data)
            clientSocket.Send(data);
        public void Close()
            _recvThread.Abort();
            clientSocket.Shutdown(SocketShutdown.Both);
            clientSocket.Close();
}

Program:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Server
    class Program
        private static Server server;
        private static void Start()
            server = new Server("127.0.0.1", 5000, 20);
        static void Main(string[] args)
            Start();//开启服务器

客户端 SocketClient类:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class ClientSocket
    private Socket _clientSocket;
    private Thread _recvThread;
    private string _rIP;  //ip地址
    private int _rProt;  //端口
    public ClientSocket(string _rIP, int _rProt)
        this._rIP = _rIP;
        this._rProt = _rProt;
        Connect();
    private void Connect()
            _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _clientSocket.Connect(new IPEndPoint(IPAddress.Parse(_rIP), _rProt));
            OnSend(Encoding.Default.GetBytes("hello,server"));
            StartRecv();
        catch
            throw;
    //开始接收消息
    private void StartRecv()
        _recvThread = new Thread(OnRecv);
        _recvThread.IsBackground = true;
        Debug.Log("开始接收消息");
        _recvThread.Start();
    //接收中
    private void OnRecv()
        while (true)
            byte[] buff = new byte[256];
            _clientSocket.Receive(buff);
            Debug.Log(Encoding.Default.GetString(buff));
    //发送信息
    public void OnSend(byte[] data)
            _clientSocket.Send(data);
        catch (Exception)
            Close();
            throw;
    public void Close()
        _recvThread.Abort();
        _clientSocket.Shutdown(SocketShutdown.Both);
        _clientSocket.Close();

调用:

using System.Net.Sockets;
using UnityEngine;
public class Client : MonoBehaviour
    private readonly string _serverIP = "127.0.0.1";//服务器ip地址