Unity實現(xiàn)簡單的多人聊天工具
更新時間:2022年02月11日 10:17:27 作者:碼字張無忌
這篇文章主要為大家詳細介紹了Unity實現(xiàn)簡單的多人聊天工具,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
本文實例為大家分享了Unity實現(xiàn)多人聊天工具的具體代碼,供大家參考,具體內(nèi)容如下
代碼1 : 服務端代碼
using UnityEngine; using System.Net.Sockets; using System.Net; using System.Threading; public class ChatServer : MonoBehaviour { ? ? ? ?// 設置連接端口 ? ? ? ?const int portNo = 500; ? ? ? ?string m_ServerIP = ""; ? ? ? ?// Use this for initialization ? ? ? ?void Start () ? ? ? ?{ ? ? ? ? ? ? ? m_ServerIP = Network.player.ipAddress;//獲取本機服務器的IP ? ? ? ? ? ?print("服務器IP:"+m_ServerIP); ? ? ? ?//開啟新的線程來執(zhí)行TCP的監(jiān)聽 ? ? ? ? ? ? ? myThread.Start (); ? ? ? ? //支持后臺運行避免最小化后不運行 ? ? ? ? ? ? ? Application.runInBackground = true; ? ? ? ?} ? ? ? ?private void ListenClientConnect () ? ? ? ?{ ? ? ? ? ? ? ? Debug.Log("正在啟動服務器!"); ? ? ? ? // 初始化服務器IP ? ? ? ? ? ?IPAddress localAdd = IPAddress.Parse(m_ServerIP); ? ? ? ? ? ? ? // 創(chuàng)建TCP偵聽器 ? ? ? ? ? ? ? TcpListener listener = new TcpListener (localAdd, portNo); ? ? ? ? ? ? ? listener.Start (); ? ? ? ? ? ?Debug.Log("服務器正在運行中......."); ? ? ? ? ? ?//溫馨提示:建議使用Windows電腦運行服務器,如果是Mac系統(tǒng)一定要看到打印這句話服務器才啟動起來了,否則服務器表示沒有啟動 ? ? ? ? // 循環(huán)接受客戶端的連接請求 ? ? ? ? while (true) { ? ? ? ? ? ? //編寫各個客戶端的類,只要監(jiān)聽到有IP連接服務器,就實例化對應的客戶端 ? ? ? ? ? ? ? ? ? ? ?ChatClient user = new ChatClient (listener.AcceptTcpClient()); ? ? ? ? ? ? ? ? ? ? ?// 顯示連接客戶端的IP與端口【只要有新的客戶端連接進來就會打印打控制臺誰進來了】 ? ? ? ? ? ? ? ? ? ? ?print (user._clientIP + " 加入服務器\n"); ? ? ? ? ? ? ? } ? ? ? ?} }
代碼2 : 客戶端與服務端交互
using UnityEngine; using System.Collections; using System.Net.Sockets; using System; using System.Text; //各個客戶端自身應該有的邏輯【進入服務器離開服務器等】 public class ChatClient : MonoBehaviour { ? ? ? ? static Hashtable ALLClients = new Hashtable ();// 客戶端列表 ? ? private TcpClient _client;// 客戶端實體 ? ? ?public string _clientIP;// 客戶端IP ? ? private string _clientNick;// 客戶端昵稱 ? ? private byte[] data;// 消息數(shù)據(jù) ? ? private bool ReceiveNick = true;//是否從客戶端接受到他的昵稱[消息分割標識] ? ? ? ?void Awake () ? ? ? ?{ ? ? ? ? ? ? ? Application.runInBackground = true; ? ? ? ?} ? ? //由服務器創(chuàng)建實例 ? ? ? ?public ChatClient (TcpClient client) ? ? ? ?{ ? ? ? ? //客戶端實體對象 ? ? ? ? ? ? ? this._client = client; ? ? ? ? ? ? ? this._clientIP = client.Client.RemoteEndPoint.ToString (); ? ? ? ? ? ? ? // 把當前客戶端實例添加到客戶列表當中 ? ? ? ? ? ? ? //第一個參數(shù)時IP,第二個為對應客戶端 ? ? ? ? ? ? ? ALLClients.Add (this._clientIP, this); ? ? ? ? ? ? ? data = new byte[this._client.ReceiveBufferSize]; ? ? ? ? ? ? ? // 從服務端獲取消息 ? ? ? ? ? ? ? client.GetStream ().BeginRead (data, 0, System.Convert.ToInt32 (this._client.ReceiveBufferSize), ReceiveMessage, null); ? ? ? ?} ? ? ? ?// 從客戶端獲取消息 ? ? ? ? void ReceiveMessage (IAsyncResult ar) ? ? ? ?{ ? ? ? ? ? ? ? int bytesRead; ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ?lock (this._client.GetStream()) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?bytesRead = this._client.GetStream ().EndRead (ar); ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? //沒有讀到數(shù)據(jù)說明這個客戶端已經(jīng)掉線 ? ? ? ? ? ? ? ? ? ? ?if (bytesRead < 1) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?ALLClients.Remove (this._clientIP); ? ? ? ? ? ? ? ? ? ? ? ? ? ?//廣播 ? ? ? ? ? ? ? ? ? ? ? ? ? ?Broadcast (this._clientNick + " 已經(jīng)離開服務器");//已經(jīng)離開服務器 ? ? ? ? ? ? ? ? ? ? ? ? ? ?return; ? ? ? ? ? ? ? ? ? ? ?} else { ? ? ? ? ? ? ? ? ? ? ? ? ? ?string messageReceived = Encoding.UTF8.GetString (data, 0, bytesRead); ? ? ? ? ? ? ? ? //這個開關很關鍵,讀取到了發(fā)送進來的數(shù)據(jù)后,默認是收到了對應客戶端的昵稱的,將這個客戶端第一次發(fā)來的信息作為昵稱,以后的都是他發(fā)消息 ? ? ? ? ? ? ? ? ? ? ? ? ? ?if (ReceiveNick) { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? this._clientNick = messageReceived; ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Broadcast (this._clientNick + " 已經(jīng)進入服務器");//已經(jīng)進入服務器 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ReceiveNick = false; ? ? ? ? ? ? ? ? ? ? ? ? ? ?} else { ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Broadcast (this._clientNick + ":" + messageReceived); ? ? ? ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ?lock (this._client.GetStream()) { ? ? ? ? ? ? ? ? //尾遞歸處理 ? ? ? ? ? ? ? ? ? ? ? ? ? ?this._client.GetStream ().BeginRead (data, 0, System.Convert.ToInt32 (this._client.ReceiveBufferSize), ReceiveMessage, null); ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? ?ALLClients.Remove (this._clientIP); ? ? ? ? ? ? ? ? ? ? ?Broadcast (this._clientNick + " 已經(jīng)離開服務器");//已經(jīng)離開服務器 ? ? ? ? ? ? ? } ? ? ? ?} ? ? ? ?// 向一個客戶端發(fā)送消息 ? ? ? ? void sendMessage (string message) ? ? ? ?{ ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ?NetworkStream ns; ? ? ? ? ? ? ? ? ? ? ?lock (this._client.GetStream()) { ? ? ? ? ? ? ? ? ? ? ? ? ? ?ns = this._client.GetStream (); ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? ? ? ? ? ?// 對信息進行編碼,寫入流,別忘記沖刷趕緊緩沖 ? ? ? ? ? ? ? ? ? ? ?byte[] bytesToSend = Encoding.UTF8.GetBytes (message); ? ? ? ? ? ? ? ? ? ? ?ns.Write (bytesToSend, 0, bytesToSend.Length); ? ? ? ? ? ? ? ? ? ? ?ns.Flush (); ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? ?Debug.Log ("Error:" + ex); ? ? ? ? ? ? ? } ? ? ? ?} ? ? ? ?// 向所有客戶端廣播消息 ? ? ? ? void Broadcast (string message) ? ? ? ?{ ? ? ? ? ? ? ? Debug.Log (message);//打印消息 ? ? ? ? //向在服務器中連接的所有客戶端發(fā)送最新消息 ? ? ? ? ? ? ? foreach (DictionaryEntry c in ALLClients) { ? ? ? ? ? ? ? ? ? ? ?((ChatClient)(c.Value)).sendMessage (message + Environment.NewLine); ? ? ? ? ? ? // ? \r是回車,英文是Carriage return ?運輸返回 ? ? ? ? ? ?B位置 ? ? ? ? ? ? // ? \n是換行,英文是New line ? ? ? ? ? ? ? ? ? ? ? ? ? ?C位置 ? ? ? ? ? ? // ? Enter = 回車+換行(\r\n) 確認按鍵 ? ? ? ? ? ? ? ? ? ?D位置 ? ? ? ? ? ? //在 Windows 環(huán)境中,C# 語言 Environment.NewLine == "\r\n" ? ? ? ? ? ? // B ? ? ? A ? ? ? ? ? ? // D ? ? ? C ? ? ? ? ? ? // 當前編輯光標位置:A ? ? ? ? ? ? //機械打字機有回車和換行兩個鍵作用分別是: ? ? ? ? ? ? //換行就是把滾筒卷一格,不改變水平位置。 ? ? ? ? ? ? //回車就是把水平位置復位,不卷動滾筒。 ? ? ? ? } ? ? } }
代碼3 : 客戶端與UI交互
using UnityEngine; using System.Net.Sockets; using System; using System.Text; using UnityEngine.UI; //各個客戶端聊天的UI交互 public class ClientHandler : MonoBehaviour { ? ? ? ?const int portNo = 500; ? ? ? ?private TcpClient _client; ? ? ? ?private ?byte[] data; ? ? ? ? string nickName = ""; ? ? ? ? string message = ""; ? ? ? ? string sendMsg = ""; ? ? ? ?[SerializeField]InputField m_NickInput; ? ? ? ?[SerializeField]InputField m_SendMsgInput; ? ? ? ?[SerializeField]Text m_ShowMessageText; ? ? [SerializeField] InputField m_IPInput; ? ? ? ?void Update () ? ? ? ?{ ? ? ? ? ? ? ? nickName = m_NickInput.text; ? ? ? ? ? ? ? m_ShowMessageText.text = message; ? ? ? ? ? ? ? sendMsg = m_SendMsgInput.text; ? ? ? ?} ? ? //連接服務器按鈕 ? ? ? ?public void ConBtnOnClik () ? ? ? ?{ ? ? ? ? ? ?if (m_IPInput.text != "" || m_IPInput.text != null) ? ? ? ? ? ?{ ? ? ? ? ? ? //真正的當前客戶端 ? ? ? ? ? ? ? ?this._client = new TcpClient(); ? ? ? ? ? ? ? ?//連接服務器的IP和端口 ? ? ? ? ? ? ? ?this._client.Connect(m_IPInput.text, portNo); ? ? ? ? ? ? ? ?//獲取緩沖區(qū)的位元組數(shù)目,即緩存區(qū)的大小 ? ? ? ? ? ? ? ?data = new byte[this._client.ReceiveBufferSize];//避免去去死,比如有些同志寫成1024 ? ? ? ? ? ? ? ?//點擊了連接服務器按鈕后就將昵稱也發(fā)送過去 ? ? ? ? ? ? ? ?SendMyMessage(nickName); ? ? ? ? ? ? //當前客戶端開始去讀取數(shù)據(jù)流 ? ? ? ? ? ? ? ?this._client.GetStream() ? ? ? ? ? ? ? ? ? ?.BeginRead(data, 0, System.Convert.ToInt32(this._client.ReceiveBufferSize), ReceiveMessage, null); ? ? ? ? ? ?} ? ? ? ? ? ?else ? ? ? ? ? ?{ ? ? ? ? ? ? ? ?Debug.Log("請輸入正確的IP"); ? ? ? ? ? ?} ? ? ? ?} ? ? //發(fā)送消息按鈕 ? ? ? ?public void SendBtnOnClik () ? ? ? ?{ ? ? ? ? //每次將輸入消息發(fā)送到服務器,并制空輸入框 ? ? ? ? ? ? ? SendMyMessage (sendMsg); ? ? ? ? ? ? ? m_SendMsgInput.text = ""; ? ? ? ?} ? ? ? ?/// <summary> ? ? ? ?/// 向服務器發(fā)送數(shù)據(jù)(發(fā)送聊天信息) ? ? ? ?/// </summary> ? ? ? ?/// <param name="message"></param> ? ? ? ? void SendMyMessage (string message) ? ? ? ?{ ? ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? ? ? ?NetworkStream ns = this._client.GetStream (); ? ? ? ? ? ? //因為我們現(xiàn)在只做文本信息的傳輸,所以這里使用UTF編碼來寫入和識別 ? ? ? ? ? ? ? ? ? ? ?byte[] data = Encoding.UTF8.GetBytes (message); ? ? ? ? ? ? ? ? ? ? ?ns.Write (data, 0, data.Length); ? ? ? ? ? ? ? ? ? ? ?ns.Flush ();//沖刷趕緊buffer緩沖,準備下次再接受新的數(shù)據(jù) ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? ?Debug.Log ("Error:" + ex); ? ? ? ? ? ? ? } ? ? ? ?} ? ? ? ?/// <summary> ? ? ? ?/// 接收服務器的數(shù)據(jù)(聊天信息) ? ? ? ?/// </summary> ? ? ? ?/// <param name="ar"></param> ? ? ? ? void ReceiveMessage (IAsyncResult ar) ? ? ? ?{ ? ? ? ? ? ? ? try { ? ? ? ? ? ? //當上面的讀取方法執(zhí)行完畢后,會自動回調(diào)這個方法 ? ? ? ? ? ? ? ? ? ? ?int bytesRead = this._client.GetStream ().EndRead (ar);//讀取完畢 ? ? ? ? ? ? ? ? ? ? ?if (bytesRead < 1) { ? ? ? ? ? ? ? ? //說明沒有讀取到任何信息 ? ? ? ? ? ? ? ? ? ? ? ? ? ?return; ? ? ? ? ? ? ? ? ? ? ?} else { ? ? ? ? ? ? ? ? //讀取到文本信息后使用UTF編碼解碼 ? ,并連續(xù)拼接起來 ? ? ? ? ? ? ? ? ? ? ? ? ? ?message += Encoding.UTF8.GetString (data, 0, bytesRead); ? ? ? ? ? ? ? ? ? ? ?} ? ? ? ? ? ? //再次去讀取信息 ? ? ? ? ? ? _client.GetStream ().BeginRead (data, 0, Convert.ToInt32 (_client.ReceiveBufferSize), ReceiveMessage, null); ? ? ? ? ? ? ? } catch (Exception ex) { ? ? ? ? ? ? ? ? ? ? ?print ("Error:" + ex); ? ? ? ? ? ? ? } ? ? ? ?} }
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
C# 連接SQL數(shù)據(jù)庫的方法及常用連接字符串
這篇文章主要介紹了C# 連接SQL數(shù)據(jù)庫的方法及常用連接字符串,有需要的朋友可以參考一下2014-01-01C#聯(lián)合VisionPro實現(xiàn)TCP/IP通信詳解
TCP/IP(傳輸控制協(xié)議/互聯(lián)網(wǎng)協(xié)議)是一組用于在網(wǎng)絡上進行通信的通信協(xié)議,本文主要為大家詳細介紹了C#如何聯(lián)合VisionPro實現(xiàn)TCP/IP通信,希望對大家有所幫助2024-02-02