客户端:
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 initialization void 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); //暂停线程500ms tcpclient.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; } } }