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