客户端:
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 ClientCore : MonoBehaviour {public static ClientCore instance = null;//建立的通讯private TcpClient client;//Stream流private NetworkStream stream;//连接是否处于活动中private bool __connected = false;public bool connected{get { return __connected; }}//接受队列public Queue<string> recvQueue = new Queue<string>();//发送队列public Queue<string> sendQueue = new Queue<string>();//缓存区大小private int maxBufferSize = 4096;//线程public Thread clientThread = null;//是否停止线程private volatile bool stop = false;//全局唯一性private void Awake () {if (instance != null){Debug.Log("严重 : ClientCore已经存在!");DestroyImmediate(gameObject);}else{DontDestroyOnLoad(gameObject);instance = this;}}private void Start(){instance = this;//stop = false;//开启客户端主线程clientThread = new Thread(new ThreadStart(StartClient));clientThread.IsBackground = true; //设为后台线程,伴随主线程关闭而关闭clientThread.Start();}//socket连接是否有效bool IsOpen(){return !((client.Client.Poll(1000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected);}//Client线程void StartClient(){byte[] recvBuf = new byte[maxBufferSize];while (!stop){if (!__connected){//尝试开启一个连接TryConnect();}//检查发送队列if (sendQueue.Count > 0 && __connected){byte[] buffer = Encoding.UTF8.GetBytes(sendQueue.Dequeue());stream.Write(buffer, 0, buffer.Length);stream.Flush();}//检查流接受数据if (stream.DataAvailable && __connected){int bytesRead = stream.Read(recvBuf, 0, maxBufferSize); //从流中获取数据,阻塞方法(如果没有数据,将阻塞线程)if (bytesRead > 0){string message = Encoding.UTF8.GetString(recvBuf);Debug.Log("收到服务器消息:" + message);recvQueue.Enqueue(message);}}//线程暂停时间(毫秒)Thread.Sleep(10);}//Close();}//尝试创建连接public void TryConnect(){CreateConnection(NetworkValue.ip, NetworkValue.port);}void CreateConnection(string host, int port){try{client = new TcpClient();client.NoDelay = true;//client.Connect(IPAddress.Parse(host), port);IAsyncResult result = client.BeginConnect(IPAddress.Parse(host), port, null, null);__connected = result.AsyncWaitHandle.WaitOne(1000, false);if (__connected){Debug.Log("连接成功!");client.EndConnect(result);}else{Debug.Log("连接失败!");client.Close();}}catch (SocketException ex){__connected = false;Debug.Log("警告:连接出现异常--> " + ex.Message);client.Close();return;}if (__connected){stream = client.GetStream();}}//将消息加入发送队列public static void Send(string item){if (instance != null)instance.Write(item);}void Write(string item){sendQueue.Enqueue(item);}//从接收队列获取一条消息public static string Recv(){if(instance!=null && instance.recvQueue.Count > 0){return instance.recvQueue.Dequeue();}return null;}//防止程序没有正确退出void OnApplicationQuit(){stop = true;if (__connected){__connected = false;stream.Close();client.Close();}if (clientThread != null && clientThread.IsAlive) {clientThread.Abort();// 如果没有正确关闭线程,这里的Join就会阻塞,就会卡死编辑器// recvProcess.Join();Debug.Log("clientThread: " + clientThread.IsAlive);}}void OnDestroy(){Debug.Log("Client OnDestroy");OnApplicationQuit();}
}
服务器端:
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;public class ServerCore : MonoBehaviour {public static ServerCore instance = null;//服务器监听端private TcpListener listener = null;//服务器主线程private Thread serverThread = null;//最大连接数量private const int maxConnected = 4;//记载所有连接的用户private static List<ClientSocket> _clients = new List<ClientSocket>();public static List<ClientSocket> clients { get { return _clients; } }//全局唯一性private void Awake(){if (instance != null){Debug.Log("严重 : ServerCore已经存在!");DestroyImmediate(gameObject);}else{DontDestroyOnLoad(gameObject);instance = this;}}// Use this for initializationvoid Start () {instance = this;//开启服务器主线程serverThread = new Thread(new ThreadStart(StartServer));serverThread.IsBackground = true; //设为后台线程,伴随主线程关闭而关闭serverThread.Start();}//服务器主线程void StartServer(){listener = new TcpListener(IPAddress.Parse(NetworkValue.ip), NetworkValue.port);Debug.Log("服务器已开启: ip-" + NetworkValue.ip + " port-" + NetworkValue.port);listener.Start();//侦测连接的客户端while (true){TcpClient tcpclient = listener.AcceptTcpClient();//已连接的客户端,阻塞方法Debug.Log("一个新用户! Client : " + tcpclient.Client.RemoteEndPoint);if (_clients.Count < maxConnected){//建立玩家连接类(开启每一个玩家的单独线程)ClientSocket client = new ClientSocket(tcpclient);_clients.Add(client);}else{//向该用户发送"已满"Thread.Sleep(500); //暂停线程500mstcpclient.Close();}}}//防止程序没有正确退出void OnApplicationQuit(){if (serverThread != null && serverThread.IsAlive){ serverThread.Abort();//serverThread.Join();Debug.Log("serverThread :"+ serverThread.IsAlive);}if (listener != null){listener.Stop();}//关闭所有用户的socket和线程foreach (ClientSocket user in _clients){if (user != null) user.Close();}}void OnDestroy(){Debug.Log("server OnDestroy");OnApplicationQuit();}//Client接收发送类public class ClientSocket{//建立的通讯private TcpClient client;//stream流private NetworkStream stream;//socket是否处于活动中private volatile bool __connected = false;public bool connected { get { return __connected; } }//接受队列public Queue<string> recvQueue = new Queue<string>();//发送队列public Queue<string> sendQueue = new Queue<string>();//缓存区大小private int maxBufferSize = 4096;//线程public Thread clientThread = null;//是否停止线程private volatile bool stop = false;//构造函数public ClientSocket(TcpClient _client){client = _client;stream = client.GetStream();//stop = false;//开启线程clientThread = new Thread(new ThreadStart(StartClient));clientThread.IsBackground = true;clientThread.Start();}//socket连接是否有效bool IsOpen(){return !((client.Client.Poll(1000, SelectMode.SelectRead) && (client.Client.Available == 0)) || !client.Client.Connected);}//Client线程void StartClient(){byte[] recvBuf = new byte[maxBufferSize];while (!stop){//连接是否有效__connected = IsOpen();//检查发送队列if (sendQueue.Count > 0 && __connected){byte[] buffer = Encoding.UTF8.GetBytes(sendQueue.Dequeue());stream.Write(buffer, 0, buffer.Length);stream.Flush();}//检查流接受数据if (stream.DataAvailable && __connected){int bytesRead = stream.Read(recvBuf, 0, maxBufferSize); //从流中获取数据,阻塞方法(如果没有数据,将阻塞线程)if (bytesRead > 0){string message = Encoding.UTF8.GetString(recvBuf);Debug.Log("收到客户端消息:" + message);recvQueue.Enqueue(message);}}//线程暂停时间(毫秒)Thread.Sleep(10); }//Close();}//添加消息到发送队列(外部方法)public void Send(string message){sendQueue.Enqueue(message);}//获取一条消息(外部方法)public string Recv(){if (recvQueue.Count <= 0){return null;}return recvQueue.Dequeue();}//关闭用户线程和socket连接public void Close(){stop = true;stream.Close();client.Close();if (clientThread != null && clientThread.IsAlive){clientThread.Abort();// 如果没有正确关闭线程,这里的Join就会阻塞,就会卡死编辑器//sendThread.Join();Debug.Log("server-clientThread: " + clientThread.IsAlive);}}}
}
配置脚本:
public class NetworkValue {//连接地址private static string _ip = "192.168.1.100";//端口号private static int _port = 1234;public static string ip{get{return _ip;}set{_ip = value;}}public static int port{get{return _port;}set{_port = value;}}
}