Unity【Socket TCP】- Un ejemplo simple de comunicación entre el servidor y el cliente

En respuesta a las necesidades de los aficionados, se hace un ejemplo de comunicación entre el servidor y el cliente.Los requisitos son relativamente simples.Usamos el protocolo Socket TCP para construir y usamos directamente el método de mensaje de longitud fija.

1. Construcción del servidor:

Abra Visual Studio, Archivo/Nuevo/Proyecto y cree una aplicación de consola:

Cree una nueva clase de servidor y una clase de cliente:

el código se muestra a continuación:

using System.Net;
using System.Net.Sockets;

namespace CoderZ
{
    public class Server
    {
        //端口
        private const int port = 8008;
        //客户端列表
        private List<Client> clients = new List<Client>();

        private static void Main(string[] args)
        {
            Console.WriteLine("服务端启动...");
            Server server = new Server();
            server.Init();
        }

        //服务端初始化
        private void Init()
        {
            TcpListener listener = new TcpListener(IPAddress.Any, port);
            listener.Start();
            try
            {
                while (true)
                {
                    Console.WriteLine("等待客户端接入...");
                    TcpClient client = listener.AcceptTcpClient();
                    Client clientInstance = new Client(client, this);
                    clients.Add(clientInstance);
                    Console.WriteLine($"{client.Client.RemoteEndPoint}接入.");
                }
            }
            catch(Exception error)
            {
                throw new Exception(error.ToString());
            }
        }

        /// <summary>
        /// 广播:向所有客户端发送数据
        /// </summary>
        /// <param name="data"></param>
        public void Broadcast(string data)
        {
            for (int i = 0; i < clients.Count; i++)
            {
                clients[i].Send(data);
            }
        }
        /// <summary>
        /// 移除客户端
        /// </summary>
        /// <param name="client"></param>
        public void Remove(Client client)
        {
            if (clients.Contains(client)) 
            { 
                clients.Remove(client);
            }
        }
    }
}
using System.Text;
using System.Net.Sockets;

namespace CoderZ
{
	public class Client
	{
		private Server server;
		private TcpClient tcpClient;
		private NetworkStream stream;

		/// <summary>
		/// 构造函数
		/// </summary>
		/// <param name="tcpClient"></param>
		/// <param name="server"></param>
		public Client(TcpClient tcpClient, Server server)
        {
			this.server = server;
			this.tcpClient = tcpClient;
			//启动线程 读取数据
			Thread thread = new Thread(TcpClientThread);
			thread.Start();
        }

		private void TcpClientThread()
        {
			stream = tcpClient.GetStream();
			//使用固定长度
			byte[] buffer = new byte[1024];

            try
            {
                while (true)
                {
					int length = stream.Read(buffer, 0, buffer.Length);
					if (length != 0)
                    {
						string data = Encoding.UTF8.GetString(buffer, 0, length);
						//解包
						Unpack(data);
                    }
                }
            }
			catch(Exception error)
            {
                Console.WriteLine(error.ToString());
            }
            finally
            {
				server.Remove(this);
            }
        }
		//拆包:解析数据
		private void Unpack(string data)
        {
            
        }
		/// <summary>
		/// 发送数据
		/// </summary>
		/// <param name="data"></param>
		public void Send(string data)
        {
			byte[] buffer = Encoding.UTF8.GetBytes(data);
			stream.Write(buffer, 0, buffer.Length);
        }
	}
}

Para el análisis de datos, usamos la herramienta LitJson.dll aquí. Si no tiene la herramienta, puede comunicarse conmigo para enviar una copia y abrir View/Solution Explorer:

Haga clic con el botón derecho en Solución/Agregar/Referencias del proyecto:

Haga clic en Examinar, busque la herramienta LitJson y haga clic en Aceptar para consultar:

Con LitJson, podemos analizar los datos, pero aún no hemos definido ninguna estructura de datos. Los datos que queremos transmitir incluyen imágenes y caracteres, por lo que aquí se define la siguiente estructura de datos:

[Serializable]
public class SimpleData
{
	/// <summary>
	/// 图片数据
	/// </summary>
	public string pic;
	/// <summary>
	/// 字符内容
	/// </summary>
	public string content;
}

Después de introducir el espacio de nombres LitJson, analice los datos:

//拆包:解析数据
private void Unpack(string data)
{
	SimpleData simpleData = JsonMapper.ToObject<SimpleData>(data);
	Console.WriteLine(simpleData.pic);
	Console.WriteLine(simpleData.content);
}

Ahora ejecuta nuestro servidor:

En segundo lugar, la construcción del cliente de Unity:

Cree una clase de Cliente, herede de MonoBehaviour y defina una estructura de datos consistente con el servidor:

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

public class Client : MonoBehaviour
{
    private string ipAddress;
    private int port;
    private bool isConnected;
    private Thread connectThread;
    private Thread readDataThread;
    private TcpClient tcpClient;
    private NetworkStream stream;
    //将数据存于队列 依次取出
    private Queue<string> queue = new Queue<string>();

    private void Start()
    {
        connectThread = new Thread(ConnectThead);
        connectThread.Start();
    }
    //连接线程
    private void ConnectThead()
    {
        tcpClient = new TcpClient();
        tcpClient.BeginConnect(ipAddress, port, ConnectThreadCallBack, tcpClient);
        float waitTime = 0f;
        while (!isConnected)
        {
            Thread.Sleep(500);
            waitTime += Time.deltaTime;
            if (waitTime > 3f)
            {
                waitTime = 0f;
                throw new Exception("连接超时");
            }
        }
    }

    private void ConnectThreadCallBack(IAsyncResult result)
    {
        tcpClient = result.AsyncState as TcpClient;
        if (tcpClient.Connected)
        {
            isConnected = true;
            tcpClient.EndConnect(result);
            stream = tcpClient.GetStream();
            readDataThread = new Thread(ReadDataThread);
            readDataThread.Start();
        }
    }
    //读取数据线程
    private void ReadDataThread()
    {
        try
        {
            while (isConnected)
            {
                byte[] buffer = new byte[1024];
                int length = stream.Read(buffer, 0, buffer.Length);
                string data = Encoding.UTF8.GetString(buffer, 0, length);
                queue.Enqueue(data);
            }
        }
        catch(Exception error)
        {
            throw new Exception(error.ToString());
        }
    }
    //程序退出时关闭线程
    private void OnApplicationQuit()
    {
        stream?.Close();
        connectThread?.Abort();
        readDataThread?.Abort();
    }

    /// <summary>
    /// 发送数据
    /// </summary>
    /// <param name="content"></param>
    public void SendData(string content)
    {
        byte[] buffer = Encoding.UTF8.GetBytes(content);
        stream.Write(buffer, 0, buffer.Length);
    }
}

[Serializable]
public class SimpleData
{
    /// <summary>
    /// 图片数据
    /// </summary>
    public string pic;
    /// <summary>
    /// 字符内容
    /// </summary>
    public string content;
}

Cree un objeto vacío y monte el script del Cliente para él:

Ejecute el programa Unity, regrese a la ventana de la consola del servidor y podrá ver que nos hemos conectado con éxito al servidor:

Encontramos una imagen, enviamos la imagen y los datos del personaje a la prueba del servidor, la colocamos en el directorio de Activos y leemos los datos de esta imagen a través del código:

 

Código de ejemplo, cuélguelo en el mismo objeto que el script del Cliente:

using System;
using System.IO;
using UnityEngine;
using LitJson;

public class Foo : MonoBehaviour
{
    private void OnGUI()
    {
        if (GUILayout.Button("发送数据", GUILayout.Width(200f), GUILayout.Height(50f)))
        {
            var bytes = File.ReadAllBytes(Application.dataPath + "/pic.jpg");
            SimpleData simpleData = new SimpleData()
            {
                pic = Convert.ToString(bytes),
                content = "这是一张汽车图片"
            };
            //使用LitJson序列化
            string data = JsonMapper.ToJson(simpleData);
            GetComponent<Client>().SendData(data);
        }
    }
}

 Ejecute el programa, haga clic en el botón enviar datos y regrese a la consola del servidor para ver que hemos recibido los datos:

Lo anterior es un ejemplo de envío de datos del cliente al servidor. A continuación, tratamos de enviar datos del servidor al cliente:

El servidor coloca la imagen en la solución como se muestra en la figura y leemos los datos de la imagen a través del código:

Enviamos datos al cliente cuando el cliente accede, por lo que lo escribiremos en el constructor del Cliente por el momento:

/// <summary>
/// 构造函数
/// </summary>
/// <param name="tcpClient"></param>
/// <param name="server"></param>
public Client(TcpClient tcpClient, Server server)
{
	this.server = server;
	this.tcpClient = tcpClient;
	//启动线程 读取数据
	Thread thread = new Thread(TcpClientThread);
	thread.Start();

	byte[] bytes = File.ReadAllBytes("pic.jpg");
	SimpleData simpleData = new SimpleData()
	{
		pic = Convert.ToBase64String(bytes),
		content = "这是一张图片"
	};
	string data = JsonMapper.ToJson(simpleData);
	Send(data);
}

En el cliente, hemos almacenado los datos enviados por el servidor en la cola, por lo que los datos se sacan de la cola a su vez:

private void Update()
{
    if (queue.Count > 0)
    {
        string data = queue.Dequeue();
        //使用LitJson反序列化
        SimpleData simpleData = JsonMapper.ToObject<SimpleData>(data);
        byte[] bytes = Convert.FromBase64String(simpleData.pic);
        //将图片存到Assets目录
        File.WriteAllBytes(Application.dataPath + "/test.jpg", bytes);
        //打印字符内容
        Debug.Log(simpleData.content);
    }
}

 

 

  Bienvenidos a la cuenta pública "Programador Salvaje Contemporáneo"

Supongo que te gusta

Origin blog.csdn.net/qq_42139931/article/details/123750597
Recomendado
Clasificación