遊戲伺服器2025年初架設與研究part11-Websocket與Unity的登入+聊天室精簡版
那先前使用Websocket的內容經過一段時間研究
也算是有了一些進展
並且先前也有人對於websocket那篇筆記一次講的內容有點太多,會不好理解
導致可能中途就遭遇了一些BUG比較難解決的
那這次就把相關的內容進行了一些精簡
讓大家可以更快速的架設好websocket的內容
當然這邊也可以當作是不同的使用方式
隨著學習各種不同的資訊,也能更清楚地理解這些其實是不同的使用方式。
因此,這方面完全可以多學幾種,以便因應各種不同的情況。
首先是Unity專案的準備
我們必須把常用的Websocket插件準備好(Unity)
https://github.com/endel/NativeWebSocket
這是較多人使用的Websocket插件
可以根據Github那邊寫的資訊進行操作匯入到Unity專案內
那我這邊也直接提供方式
首先在你的Unity專案中,上方的選單選擇Window
底下選到Package Manager
打開Package Manager
點選有URL的選項(Install package from git URL)
接著請在這個URL框內輸入對應的內容
也就是https://github.com/endel/NativeWebSocket.git#upm
輸入好之後就點擊最右邊的install安裝就好了
輸入好之後就點擊最右邊的install安裝就好了
安裝好會如圖這樣我們可以看到Native WebSockets插件會在這個位置
如果需要更新,可以在右邊的選單點Update即可
這樣在Unity內就可以使用Websocket相關的語法了
接著我們回到伺服器的地方,也就是我們的Ubuntu server
首先確保在虛擬環境當中進行安裝websocket插件
簡單的確認方式就是看現在輸入的位置前方有無(venv)
確認好之後可以進行安裝pip install websockets
接著請在想要執行的位置新增一個python檔案(.py)
我這邊是在自己電腦的python專案內新增了一個python檔案main.py
內容如下
import asyncio
import websockets
import json
connected = set()
async def echo(websocket):
print("新的連線")
connected.add(websocket)
try:
async for message in websocket:
try:
data = json.loads(message)
if data["type"] == "login":
username = data["username"]
print(f"{username} 登入了")
await websocket.send(json.dumps({"type": "welcome", "message": f"歡迎 {username}"}))
elif data["type"] == "chat":
msg = data["message"]
for conn in connected:
await conn.send(json.dumps({"type": "chat", "message": msg}))
except Exception as e:
print("解析錯誤", e)
finally:
connected.remove(websocket)
async def main():
async with websockets.serve(echo, "localhost", 8765):
print("WebSocket server started on ws://localhost:8765")
await asyncio.Future() # 永不結束,讓 server 一直跑下去
if __name__ == "__main__":
asyncio.run(main())
先簡單說明一下這個程式碼的功能
主要就是websocket建立連線
之後可以透過type=chat發送聊天訊息給其他連線使用者
準備好伺服器的程式碼之後,我們就回到Unity專案之中
首先在我們專案內準備一個放置腳本的區域(資料夾)
那我這邊是放在A_Scripts之中
點專案空白處右鍵,可以選擇Create->MonoBehaviour Script
接著就可以建立新的C#腳本
接著取名WebSocketClient
當然這邊名稱可以取自己想要的,不過為了避免等等出錯,暫時先取固定的
等熟練後都可以再進行替換
using System;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using NativeWebSocket;
[Serializable]
public class ClientPacket
{
public string type;
public string username;
public string message;
}
[Serializable]
public class ServerPacket
{
public string type;
public string message;
}
public class WebSocketClient : MonoBehaviour
{
private WebSocket websocket;
// 設定伺服器位址
[SerializeField]
private string serverUrl = "ws://localhost:8765";
private async void Start()
{
websocket = new WebSocket(serverUrl);
websocket.OnOpen += OnOpen;
websocket.OnError += OnError;
websocket.OnClose += OnClose;
websocket.OnMessage += OnMessage;
await websocket.Connect();
}
private void Update()
{
#if !UNITY_WEBGL || UNITY_EDITOR
websocket?.DispatchMessageQueue();
#endif
}
private void OnApplicationQuit()
{
websocket?.Close();
}
private void OnOpen()
{
Debug.Log("WebSocket opened.");
}
private void OnError(string errorMsg)
{
Debug.LogError("WebSocket error: " + errorMsg);
}
private void OnClose(WebSocketCloseCode closeCode)
{
Debug.Log("WebSocket closed with code: " + closeCode);
}
private void OnMessage(byte[] bytes)
{
string json = Encoding.UTF8.GetString(bytes);
try
{
ServerPacket packet = JsonUtility.FromJson<ServerPacket>(json);
switch (packet.type)
{
case "welcome":
Debug.Log(packet.message);
break;
case "chat":
Debug.Log("Chat: " + packet.message);
break;
default:
Debug.LogWarning($"Unknown packet type: {packet.type}");
break;
}
}
catch (Exception e)
{
Debug.LogError("Failed to parse server packet: " + e);
}
}
public async Task SendLogin(string username)
{
ClientPacket packet = new ClientPacket
{
type = "login",
username = username
};
string json = JsonUtility.ToJson(packet);
await websocket.SendText(json);
}
public async Task SendChat(string message)
{
ClientPacket packet = new ClientPacket
{
type = "chat",
message = message
};
string json = JsonUtility.ToJson(packet);
await websocket.SendText(json);
}
}
主要的程式碼就這些
這樣就已經具備了基本的Websocket收送功能
首先可以看到我們Start進行了新增Websocket連線的動作
相關事件也是在那邊處理的
處理完之後會進行連線
接下來就可以等待連線完成
Update則是會處理收到的websocket封包
OnApplicationQuit是應用程式結束的時候會處理斷線
並且我也在多數程式碼當中加上了log訊息,可以直接從Unity的console當中確認狀態
那其中最重要的幾個function是需要注意的,也就是最底下的SendLogin跟SendChat
這是我們等等要處理發送觸發的事件的地方
那為了方便理解,我們拆到另一個腳本進行處理
這邊我們再新增一個腳本UiSendEvent
using UnityEngine;
using TMPro;
public class UiSendEvent : MonoBehaviour
{
public WebSocketClient webSocketClient = null;
public async void OnClickLoginBtn(TMP_InputField inputText)
{
string input = inputText.text;
await webSocketClient.SendLogin(input);
}
public async void OnClickChatBtn(TMP_InputField inputText)
{
string input = inputText.text;
await webSocketClient.SendChat(input);
}
}
裡面加上這些內容
那這邊注意一下如果使用的是舊版Text
那上方改成using UnityEngine.UI
然後底下用InputField
接著我們要到場景內新增物件
首先假設我們是一個新場景,場景內沒有任何物件
也就是從Hierarchy看沒有任何東西的場景
點右鍵,新增空物件Create Empty也可以按右邊顯示的快捷鍵
取名叫做Manager,當然這邊名稱可以隨意取,不會影響到功能
選擇物件後,把剛剛兩個新腳本都添加上去
可以直接拖曳兩個腳本,拉到Add Component底下的區域放開
這樣就添加上去了
另外也可以透過點擊Add Component去個別添加腳本
這邊注意一點,想要同時添加多個腳本,也就是說會需要複選腳本
那這邊請在選角本前先把Inspector上鎖,避免選擇的東西跑掉
這邊注意右上角
鎖頭點了之後,就可以暫時把視窗鎖定
不會因為你選了別的東西而視窗跑掉
這樣就可以一次拉兩個腳本上來
操作完之後可以再次點擊鎖頭,就可以取消鎖定
如果不想按上鎖的操作,那只要一次只拉一個腳本
這樣重複兩次也能把兩個腳本拉上來
添加上兩個腳本後,就會如上圖底下的樣子
接下來我們先把缺的東西給拉上去可以看到Web Socket Client這邊右邊還顯示著None
表示還缺少東西,我們點選旁邊的按紐
選取右邊的點後,就會跳出如左邊的視窗,開頭Select ....的視窗
那我們可以看到剛剛取好名稱的Manager
這是Unity內建替我們找到場景內有掛這個腳本的物件
當然如果你掛很多個,這邊就會找到一堆
所以請確保只有掛一個
掛上後,物件底下應該會長這個樣子接下來我們繼續把缺少的UI給一一創建出來
在Hierarchy視窗點右建,繼續創建物件
我們選擇UI->Button - TextMeshPro
如果是較舊的Unity版本,會是單純的Button
不過功能基本一樣,只是要using不同而已(如前面提到的)
按照我們剛剛的邏輯
我們會需要兩個Button跟兩個InputField
而場景中出現的Canvas跟EventSystem
他們分別是管理UI自動被創建的物件
另一個是管理Buttom等點擊事件的管理器
兩者都是自動生成,我們暫時不用管他們
我們把按鈕跟輸入框進行對應排列了一下
還記得我們先前的腳本,是有帶參數的,參數型別就是TMP_InputField
所以直接去場景中拉取對應的參數
這邊要注意不要拉錯了
因為我們目前兩個名稱沒有改,所以看起來會是一樣的
如果怕搞錯,可以先取成不同的名字,這樣拉上去就會長不一樣
處理完一個之後還有另一個Button
就按照相同的邏輯把另一個Chat的Button處理好
這樣一切就準備就緒了
我們先回到server的地方
這邊我們先執行我們先前準備好的python腳本
python3 main.py
輸入以上指令
如果沒有報錯,就會看到以下的指令
WebSocket server started on ws://localhost:8765
這樣就表示伺服器已經架好了
當然這邊要注意,如果cloudflare等等的轉發沒有設定就要先去看先前幾篇的筆記
如果暫時不想設置也沒關係,測試期間可以暫時使用區域網路進行測試
也就是如我上面範例使用的網址,但是記得IP要換成內網對應的IP
要修改的主要就是
把這邊的Url改成自己的接下來我們就可以點擊Unity的play來檢查效果了
點上方play開始測試首先我們play之後
應該就能從Console看到連線成功的訊息了
當然我們可以隨時調整它的位置
然後在右邊輸入我們想要傳給Server的訊息
我這邊就簡單的輸入了名稱John跟聊天內容Hi這邊可以隨意輸入
因為我們先前已經有加上log了
這邊送出後,就直接從Console視窗查看訊息
確認Client端沒有問題後,可以去檢查一下伺服器那邊我們應該就可以看到先前準備的log訊息
這樣就算是完成這次的測試與分享
並且這個聊天功能也就支援建立連線後,每個發送訊息
都可以讓整個連線內的所有人收到
舉例來說假設有100人都建立了這個websocket連線
那發送這個chat就能讓伺服器轉發給有建立連線的100位使用者
而這100位使用者就可以根據伺服器廣播的資訊來進行聊天室訊息的顯示與處理
大家也可以自行測試
這次就分享到這邊,如有疑問,也可以提出~
留言
張貼留言