Unity基于TCP的C/S网络传输

背景

开发过程中,联网发送信息,在现在是不可以避免的,客户端之间需要数据相互同步,达到人人互联。

原理开发

这是一套基于TCP网络传送方案,Unity开发的客户端以及服务端,局域网内测试完全通过(有需要的朋友,可以,部署自己的服务器,配置公网IP和端口号即可使用),关于中文传输现在显示的???,可将发送和接受数据格式 Encoding.ASCII转变成 Encoding.UTF8即可。注意:一定要在PC端开启Server,模拟器安卓端将无法获取端口号,开启Server会报错!

核心代码

服务端代码:

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

public class TCPTestServer : MonoBehaviour
{
	[Serializable]
	public class ClientData
	{
		public static int MAX_ID;
		
		public int ID;
		public string Name;
	}
	
	public class ConnectedClient
	{
		public ClientData ClientData;
		public TcpClient Client;

		public ConnectedClient(ClientData data, TcpClient client)
		{
			ClientData = data;
			Client = client;
		}
	}

	[Serializable]
	public class ServerMessage
	{
		public ClientData SenderData;
		public string Data;

		public ServerMessage(ClientData client, string message)
		{
			SenderData = client;
			Data = message;
		}
	}
	
	public Action<string> OnLog = delegate{};
	
	public bool IsConnected
	{
		get { return tcpListenerThread != null && tcpListenerThread.IsAlive; }
	}
	
	public string IPAddress = "127.0.0.1";
	public int Port = 8052;
	
	/// <summary> 	
	/// TCPListener to listen for incoming TCP connection 	
	/// requests. 	
	/// </summary> 	
	private TcpListener tcpListener;

	/// <summary> 
	/// Background thread for TcpServer workload. 	
	/// </summary> 	
	private Thread tcpListenerThread;

	private List<ConnectedClient> connectedClients = new List<ConnectedClient>();

	// Use this for initialization
	public void StartServer()
	{
		// Start TcpServer background thread 		
		tcpListenerThread = new Thread(ListenForIncomingRequests);
		tcpListenerThread.IsBackground = true;
		tcpListenerThread.Start();
	}

	/// <summary> 	
	/// Runs in background TcpServerThread; Handles incoming TcpClient requests 	
	/// </summary> 	
	private void ListenForIncomingRequests()
	{
		try
		{
			// Create listener on localhost port 8052. 			
			tcpListener = new TcpListener(System.Net.IPAddress.Any, Port);
			tcpListener.Start();
			
			ThreadPool.QueueUserWorkItem(ListenerWorker, null);
			OnLog("Server is listening");
		}
		catch (SocketException socketException)
		{
			OnLog("SocketException " + socketException);
		}
	}

	private void ListenerWorker(object token)
	{
		while (tcpListener != null)
		{
			var client = tcpListener.AcceptTcpClient();
			ThreadPool.QueueUserWorkItem(HandleClientWorker, client);
		}
	}
	
	private void HandleClientWorker(object token)
	{
		Byte[] bytes = new Byte[1024];
		using (TcpClient client = token as TcpClient)
		{
			ClientData data = new ClientData();
			data.ID = ++ClientData.MAX_ID;
			data.Name = "User" + data.ID;

			ConnectedClient connectedClient = new ConnectedClient(data, client);
			connectedClients.Add(connectedClient);
			OnLog(string.Format("{0} has Connected as {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address, data.Name));
			DispatchMessage(new ServerMessage(data, "Client Connected"));

			// Get a stream object for reading
			try
			{
				using (NetworkStream stream = client.GetStream())
				{
					int length;
					// Read incoming stream into byte array. 						
					while (stream.CanRead && (length = stream.Read(bytes, 0, bytes.Length)) != 0)
					{
						var incomingData = new byte[length];
						Array.Copy(bytes, 0, incomingData, 0, length);
                        // Convert byte array to string message.
                        //string clientMessage = Encoding.UTF8.GetString(incomingData, 0, length);
                        string clientMessage = Encoding.ASCII.GetString(incomingData);
						//OnLog("Server received: " + clientMessage);
							
						if (clientMessage == "!disconnect")
						{
							stream.Close();
							client.Close();
						}
						
						ServerMessage serverMessage = new ServerMessage(data, clientMessage);
						if (clientMessage.StartsWith("!"))
						{
							ProcessMessage(connectedClient, clientMessage);
						}
						else
						{
							DispatchMessage(serverMessage);
						}
					}
				}
			}
			catch (SocketException e)
			{
				OnLog(e.ToString());
			}
		}
	}

	private void ProcessMessage(ConnectedClient connectedClient, string command)
	{
		string[] split = command.Split(' ');
		string response = string.Empty;
		ServerMessage serverMessage = null;
		switch (split[0])
		{
				case "!disconnect":
					response = (string.Format("{0} has Disconnected", connectedClient.ClientData.Name));
					OnLog(response);
					DisconnectClient(connectedClient);
					break;
				case "!ping":
					response = String.Join(" ", split) + " " + (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds;
					serverMessage = new ServerMessage(connectedClient.ClientData, response);
					SendMessage(connectedClient.Client, serverMessage);
					break;
				default:
					response = "Unknown Command '" + command + "'";
					serverMessage = new ServerMessage(connectedClient.ClientData, response);
					SendMessage(connectedClient.Client, serverMessage);
					break;
		}
	}

	private void DispatchMessage(ServerMessage serverMessage)
	{
		for (int i = 0; i < connectedClients.Count; i++)
		{
			ConnectedClient connection = connectedClients[i];
			TcpClient client = connection.Client;
			if (!SendMessage(client, serverMessage))
			{
				OnLog(string.Format("Lost connection with {0}", connection.ClientData.Name));
				DisconnectClient(connection);
				i--;
			}
		}
	}

	private void DisconnectClient(ConnectedClient connection)
	{
		connectedClients.Remove(connection);
	}

	/// <summary> 	
	/// Send message to client using socket connection. 	
	/// </summary> 	
	private bool SendMessage(TcpClient client, ServerMessage serverMessage)
	{
		if (client != null && client.Connected)
		{
			try
			{
				// Get a stream object for writing. 			
				NetworkStream stream = client.GetStream();
				if (stream.CanWrite)
				{
                    // Convert string message to byte array.           
                    //  byte[] serverMessageAsByteArray = Encoding.UTF8.GetBytes(JsonUtility.ToJson(serverMessage));
                    byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(JsonUtility.ToJson(serverMessage));
					// Write byte array to socketConnection stream.               
					stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
					return true;
				}
			}
			catch (SocketException socketException)
			{
				OnLog("Socket exception: " + socketException);
			}
		}

		return false;
	}
}

客户端代码:

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

public class TCPTestClient : MonoBehaviour
{
	public Action<TCPTestClient> OnConnected = delegate{};
	public Action<TCPTestClient> OnDisconnected = delegate{};
	public Action<string> OnLog = delegate{};
	public Action<TCPTestServer.ServerMessage> OnMessageReceived = delegate{};

	public bool IsConnected
	{
		get { return socketConnection != null && socketConnection.Connected; }
	}

	public string IPAddress = "127.0.0.1";
	public int Port = 8052;
	
	private TcpClient socketConnection;
	private Thread clientReceiveThread;
	private NetworkStream stream;
	private bool running;


	/// <summary> 	
	/// Setup socket connection. 	
	/// </summary> 	
	public void ConnectToTcpServer()
	{
		try
		{
			OnLog(string.Format("Connecting to {0}:{1}", IPAddress, Port));
			clientReceiveThread = new Thread(new ThreadStart(ListenForData));
			clientReceiveThread.IsBackground = true;
			clientReceiveThread.Start();
		}
		catch (Exception e)
		{
			OnLog("On client connect exception " + e);
		}
	}

	/// <summary> 	
	/// Runs in background clientReceiveThread; Listens for incoming data. 	
	/// </summary>     
	private void ListenForData()
	{
		try
		{
			socketConnection = new TcpClient(IPAddress, Port);
			OnConnected(this);
			OnLog("Connected");
			
			Byte[] bytes = new Byte[1024];
			running = true;
			while (running)
			{
				// Get a stream object for reading
				using (stream = socketConnection.GetStream())
				{
					int length;
					// Read incoming stream into byte array. 					
					while (running && stream.CanRead)
					{
						length = stream.Read(bytes, 0, bytes.Length);
						if (length != 0)
						{
							var incomingData = new byte[length];
							Array.Copy(bytes, 0, incomingData, 0, length);
                            // Convert byte array to string message. 	
                            //string serverJson = Encoding.UTF8.GetString(incomingData, 0, length);
                            string serverJson = Encoding.ASCII.GetString(incomingData);
							TCPTestServer.ServerMessage serverMessage = JsonUtility.FromJson<TCPTestServer.ServerMessage>(serverJson);
							MessageReceived(serverMessage);
						}
					}
				}
			}
			socketConnection.Close();
			OnLog("Disconnected from server");
			OnDisconnected(this);
		}
		catch (SocketException socketException)
		{
			OnLog("Socket exception: " + socketException);
		}
	}

	public void CloseConnection()
	{
		SendMessage("!disconnect");
		running = false;
	}

	public void MessageReceived(TCPTestServer.ServerMessage serverMessage)
	{
		OnMessageReceived(serverMessage);
	}

	/// <summary> 	
	/// Send message to server using socket connection. 	
	/// </summary> 	
	public bool SendMessage(string clientMessage)
	{
		if (socketConnection != null && socketConnection.Connected)
		{
			try
			{
				// Get a stream object for writing. 			
				NetworkStream stream = socketConnection.GetStream();
				if (stream.CanWrite)
				{
                    // Convert string message to byte array.                 
                    // byte[] clientMessageAsByteArray = Encoding.UTF8.GetBytes(clientMessage);
                    byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
					// Write byte array to socketConnection stream.                 
					stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
					OnSentMessage(clientMessage);
					return true;
				}
			}
			catch (SocketException socketException)
			{
				OnLog("Socket exception: " + socketException);
			}
		}

		return false;
	}

	public virtual void OnSentMessage(string message)
	{
	}
}

演示视频:
https://live.csdn.net/v/110261
有需要的,可自取Demo_011
https://blog.csdn.net/qq_25122429/article/details/114098885

Unity中使用TCP协议传输数据可以通过使用C#中的Socket类来实现。下面是一个简单的示例代码,展示了如何在Unity中使用TCP协议传输数据: ```csharp using System; using System.Net; using System.Net.Sockets; using System.Text; using UnityEngine; public class TCPClient : MonoBehaviour { private TcpClient client; private NetworkStream stream; private byte[] receiveBuffer; private void Start() { ConnectToServer("127.0.0.1", 8888); // 连接到服务器的IP和端口 } private void ConnectToServer(string serverIP, int serverPort) { try { client = new TcpClient(); client.Connect(serverIP, serverPort); stream = client.GetStream(); receiveBuffer = new byte[1024]; // 启动异步接收数据 stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, OnReceiveData, null); } catch (Exception e) { Debug.Log("连接服务器失败:" + e.Message); } } private void OnReceiveData(IAsyncResult ar) { try { int bytesRead = stream.EndRead(ar); if (bytesRead <= 0) { Debug.Log("与服务器断开连接"); return; } string receivedMessage = Encoding.ASCII.GetString(receiveBuffer, 0, bytesRead); Debug.Log("收到服务器消息:" + receivedMessage); // 继续异步接收数据 stream.BeginRead(receiveBuffer, 0, receiveBuffer.Length, OnReceiveData, null); } catch (Exception e) { Debug.Log("接收数据时发生错误:" + e.Message); } } private void SendMessageToServer(string message) { try { byte[] data = Encoding.ASCII.GetBytes(message); stream.Write(data, 0, data.Length); Debug.Log("发送消息到服务器:" + message); } catch (Exception e) { Debug.Log("发送消息时发生错误:" + e.Message); } } private void OnDestroy() { if (stream != null) stream.Close(); if (client != null) client.Close(); } // 示例使用的按钮点击事件 public void SendButtonOnClick() { SendMessageToServer("Hello, Server!"); } } ``` 以上示例代码是一个简单的TCP客户端,它通过Socket连接到指定的服务器IP和端口,然后可以发送和接收数据。你可以根据自己的需求进行修改和扩展。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

W低小调W

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值