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://pan.baidu.com/s/1CP4FLttldNHW-gW2zUrlDA
提取码:ncv6

posted @ 2020-11-29 13:41  低小调  阅读(255)  评论(0编辑  收藏  举报