首頁 > 軟體

Unity實現簡單的多人聊天工具

2022-02-11 13:02:14

本文範例為大家分享了Unity實現多人聊天工具的具體程式碼,供大家參考,具體內容如下

程式碼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);
       //開啟新的執行緒來執行TCP的監聽
              myThread.Start ();
        //支援後臺執行避免最小化後不執行
              Application.runInBackground = true;
       }
       private void ListenClientConnect ()
       {
              Debug.Log("正在啟動伺服器!");
        // 初始化伺服器IP
           IPAddress localAdd = IPAddress.Parse(m_ServerIP);
              // 建立TCP偵聽器
              TcpListener listener = new TcpListener (localAdd, portNo);
              listener.Start ();
           Debug.Log("伺服器正在執行中.......");
           //溫馨提示:建議使用Windows電腦執行伺服器,如果是Mac系統一定要看到列印這句話伺服器才啟動起來了,否則伺服器表示沒有啟動
        // 迴圈接受使用者端的連線請求
        while (true) {
            //編寫各個使用者端的類,只要監聽到有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;// 訊息資料

    private bool ReceiveNick = true;//是否從使用者端接受到他的暱稱[訊息分割標識]

       void Awake ()
       {
              Application.runInBackground = true;
       }

    //由伺服器建立範例
       public ChatClient (TcpClient client)
       {
        //使用者端實體物件
              this._client = client;

              this._clientIP = client.Client.RemoteEndPoint.ToString ();

              // 把當前使用者端範例新增到客戶列表當中
              //第一個引數時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);
                     }
            //沒有讀到資料說明這個使用者端已經掉線
                     if (bytesRead < 1) {
                           ALLClients.Remove (this._clientIP);
                           //廣播
                           Broadcast (this._clientNick + " 已經離開伺服器");//已經離開伺服器

                           return;
                     } else {
                           string messageReceived = Encoding.UTF8.GetString (data, 0, bytesRead);
                //這個開關很關鍵,讀取到了傳送進來的資料後,預設是收到了對應使用者端的暱稱的,將這個使用者端第一次發來的資訊作為暱稱,以後的都是他發訊息
                           if (ReceiveNick) {
                                  this._clientNick = messageReceived;
                                  Broadcast (this._clientNick + " 已經進入伺服器");//已經進入伺服器
                                  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 + " 已經離開伺服器");//已經離開伺服器
              }
       }

       // 向一個客戶端傳送訊息
        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);//列印訊息
        //向在伺服器中連線的所有使用者端傳送最新訊息
              foreach (DictionaryEntry c in ALLClients) {
                     ((ChatClient)(c.Value)).sendMessage (message + Environment.NewLine);

            //   r是回車,英文是Carriage return  運輸返回            B位置
            //   n是換行,英文是New line                            C位置
            //   Enter = 回車+換行(rn) 確認按鍵                    D位置
            //在 Windows 環境中,C# 語言 Environment.NewLine == "rn"

            // 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);
               //獲取緩衝區的位元組數目,即快取區的大小
               data = new byte[this._client.ReceiveBufferSize];//避免去去死,比如有些同志寫成1024
               //點選了連線伺服器按鈕後就將暱稱也傳送過去
               SendMyMessage(nickName);

            //當前使用者端開始去讀取資料流
               this._client.GetStream()
                   .BeginRead(data, 0, System.Convert.ToInt32(this._client.ReceiveBufferSize), ReceiveMessage, null);
           }
           else
           {
               Debug.Log("請輸入正確的IP");
           }
       }
    //傳送訊息按鈕
       public void SendBtnOnClik ()
       {
        //每次將輸入訊息傳送到伺服器,並制空輸入框
              SendMyMessage (sendMsg);
              m_SendMsgInput.text = "";
       }

       /// <summary>
       /// 向伺服器傳送資料(傳送聊天資訊)
       /// </summary>
       /// <param name="message"></param>
        void SendMyMessage (string message)
       {
              try {
                     NetworkStream ns = this._client.GetStream ();
            //因為我們現在只做文字資訊的傳輸,所以這裡使用UTF編碼來寫入和識別
                     byte[] data = Encoding.UTF8.GetBytes (message);

                     ns.Write (data, 0, data.Length);
                     ns.Flush ();//沖刷趕緊buffer緩衝,準備下次再接受新的資料
              } catch (Exception ex) {
                     Debug.Log ("Error:" + ex);
              }
       }

       /// <summary>
       /// 接收伺服器的資料(聊天資訊)
       /// </summary>
       /// <param name="ar"></param>
        void ReceiveMessage (IAsyncResult ar)
       {
              try {
            //當上面的讀取方法執行完畢後,會自動回撥這個方法
                     int bytesRead = this._client.GetStream ().EndRead (ar);//讀取完畢

                     if (bytesRead < 1) {
                //說明沒有讀取到任何資訊
                           return;
                     } else {
                //讀取到文字資訊後使用UTF編碼解碼   ,並連續拼接起來
                           message += Encoding.UTF8.GetString (data, 0, bytesRead);
                     }
            //再次去讀取資訊
            _client.GetStream ().BeginRead (data, 0, Convert.ToInt32 (_client.ReceiveBufferSize), ReceiveMessage, null);
              } catch (Exception ex) {
                     print ("Error:" + ex);
              }
       }

}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。


IT145.com E-mail:sddin#qq.com