北京建站設(shè)計(jì)寫(xiě)一篇軟文1000字
概述
在現(xiàn)代多人在線游戲中,穩(wěn)定且高效的網(wǎng)絡(luò)通信是確保游戲體驗(yàn)的關(guān)鍵。本文將探討如何利用C#開(kāi)源網(wǎng)絡(luò)通信庫(kù)PESocket來(lái)構(gòu)建一個(gè)簡(jiǎn)單的Unity客戶端與.NET控制臺(tái)服務(wù)器之間的實(shí)時(shí)消息傳遞系統(tǒng)。通過(guò)本例,讀者不僅能夠了解PESocket的基本用法,還將學(xué)到一些關(guān)于設(shè)計(jì)跨平臺(tái)網(wǎng)絡(luò)應(yīng)用程序的最佳實(shí)踐。
1. PESocket簡(jiǎn)介
PESocket開(kāi)源項(xiàng)目GitHub地址:點(diǎn)擊跳轉(zhuǎn)
博客地址:C#開(kāi)源網(wǎng)絡(luò)通信庫(kù)PESocket的使用 - PlaneZhong - 博客園 (cnblogs.com)
PESocket是一個(gè)輕量級(jí)、易于使用的網(wǎng)絡(luò)通信框架,特別適合于快速原型制作和小規(guī)模項(xiàng)目。它基于Socket編程模型,并提供了簡(jiǎn)潔的API以簡(jiǎn)化異步數(shù)據(jù)傳輸過(guò)程。
不用過(guò)多了解網(wǎng)絡(luò)通信內(nèi)部原理,只需幾行簡(jiǎn)單的代碼,便能簡(jiǎn)捷快速開(kāi)發(fā)基于C#語(yǔ)言的服務(wù)器和客戶端,實(shí)現(xiàn)網(wǎng)絡(luò)通信。
2. 序列化與反序列化
為了在網(wǎng)絡(luò)間安全高效地傳輸復(fù)雜對(duì)象,PESocket采用了自定義的序列化機(jī)制。這使得任何實(shí)現(xiàn)了ISerializable
接口或標(biāo)記了[Serializable]
屬性的數(shù)據(jù)結(jié)構(gòu)都可以被直接打包成二進(jìn)制流發(fā)送出去,到達(dá)目的地后再恢復(fù)為原始形式。
3. 會(huì)話管理
每個(gè)連接到服務(wù)器的客戶端都由一個(gè)獨(dú)立的PESession
實(shí)例代表,負(fù)責(zé)處理所有相關(guān)的輸入輸出操作。這種一對(duì)一的關(guān)系有助于實(shí)現(xiàn)更細(xì)粒度的安全控制及錯(cuò)誤處理策略。
4. 日志記錄
良好的日志記錄習(xí)慣對(duì)于調(diào)試和維護(hù)網(wǎng)絡(luò)應(yīng)用至關(guān)重要。PESocket內(nèi)置了一套強(qiáng)大的日志系統(tǒng),可以根據(jù)不同級(jí)別(如信息、警告、錯(cuò)誤等)記錄詳細(xì)的運(yùn)行時(shí)狀態(tài)變化。
開(kāi)發(fā)步驟
第一步:設(shè)置項(xiàng)目環(huán)境
- 創(chuàng)建一個(gè)新的Unity項(xiàng)目作為客戶端。
- 新建一個(gè)標(biāo)準(zhǔn)的.NET控制臺(tái)應(yīng)用程序充當(dāng)服務(wù)器角色。
- 在兩個(gè)項(xiàng)目中分別導(dǎo)入PESocket引用
網(wǎng)絡(luò)協(xié)議必須要去繼承自PESocket里的PEMsg
服務(wù)器里PESocket 放在網(wǎng)絡(luò)模塊
將協(xié)議里原來(lái)的引用都刪除-添加引用-找到之前生成的PESocket.dll
將原來(lái)服務(wù)器里的引用都刪除-添加引用-直接引用協(xié)議項(xiàng)目
第二步:定義通信協(xié)議
服務(wù)器需要與客戶端進(jìn)行通信,需要一個(gè)網(wǎng)絡(luò)協(xié)議(類(lèi)庫(kù))
首先,我們需要定義一個(gè)共享的消息類(lèi),用于封裝待交換的信息。此例中我們僅包含了一個(gè)字符串字段text
,但根據(jù)實(shí)際需求可以擴(kuò)展更多屬性。
// NetMsg.cs
using PENet;
using System;namespace PEProtocal
{[Serializable]public class NetMsg : PEMsg{public string text;}public class IPCfg{public const string srvIP = "127.0.0.1";public const int srvPort = 17666;}
}
第三步:編寫(xiě)服務(wù)器端代碼
接下來(lái)創(chuàng)建服務(wù)器邏輯,包括初始化監(jiān)聽(tīng)器以及處理來(lái)自遠(yuǎn)程主機(jī)的各種事件。
有了ip端口信息就可以在服務(wù)器(ServerStart)里生成一個(gè)PESocket
但由于PESocket需要有一個(gè)進(jìn)行網(wǎng)絡(luò)通信的Session,并且這個(gè)Session需要繼承自PESession
在服務(wù)器下創(chuàng)建一個(gè)session(類(lèi)):ServerSession
ServerSession負(fù)責(zé)與客戶端進(jìn)行連接
連接后需做
1.建立連接時(shí)需要有一個(gè)反饋
2.收到數(shù)據(jù)時(shí)對(duì)數(shù)據(jù)進(jìn)行處理
3.斷開(kāi)連接時(shí)打出一個(gè)反饋日志
using Protocal;
using PENet;/// <summary>
/// ServerSession負(fù)責(zé)與客戶端進(jìn)行連接
/// </summary>
public class ServerSession:PESession<NetMsg>//PESession需要傳入網(wǎng)絡(luò)消息的類(lèi)
{//建立連接protected override void OnConnected(){PETool.LogMsg("Client Connect");//PESocket里封裝好的方法SendMsg(new NetMsg{text = "Welcome to connect."});}//收到數(shù)據(jù)protected override void OnReciveMsg(NetMsg msg){PETool.LogMsg("Client Req:" + msg.text);SendMsg(new NetMsg{text = "SrvRsp:" + msg.text});}//斷開(kāi)連接protected override void OnDisConnected(){PETool.LogMsg("Client DisConnect");}}
在服務(wù)器端,
ServerStart
類(lèi)是整個(gè)應(yīng)用的入口點(diǎn)。它負(fù)責(zé)初始化網(wǎng)絡(luò)通信服務(wù),并保持服務(wù)器運(yùn)行狀態(tài)以便持續(xù)監(jiān)聽(tīng)來(lái)自客戶端的連接請(qǐng)求。?
using PENet;
using Protocal;/// <summary>
/// 服務(wù)器
/// </summary>
namespace Server
{class ServerStart{static void Main(string[] args){//需要一個(gè)進(jìn)行網(wǎng)絡(luò)通信的Session,并且這個(gè)Session需要繼承自PESession,還有一個(gè)網(wǎng)絡(luò)消息的類(lèi)(協(xié)議)PESocket<ServerSession, NetMsg> server = new PESocket<ServerSession, NetMsg>();server.StartAsServer(IPCfg.srvIP, IPCfg.srvPort);//需要傳遞的ip和端口while (true){/* Keep the application running */}}}
}
第四步:配置Unity客戶端
現(xiàn)在轉(zhuǎn)向Unity工程,在MonoBehaviour腳本中添加必要的邏輯以便建立與遠(yuǎn)端服務(wù)的鏈接并發(fā)送/接收文本消息。
將協(xié)議工程導(dǎo)出(給客戶端使用)
屬性-生成 更改路徑 生成-重新生成解決方案
unity里直接導(dǎo)入PESocket與協(xié)議dll
客戶端也需要一個(gè)Session
Session 用來(lái)和客戶端進(jìn)行連接,每個(gè)客戶端對(duì)應(yīng)一個(gè)session(只用關(guān)聯(lián)自己),服務(wù)器對(duì)應(yīng)多個(gè)客戶端(有多個(gè)session)??
using PENet;
using Protocal;
using UnityEngine;public class ClientSession:PESession<NetMsg>
{//建立連接protected override void OnConnected(){//PETool.LogMsg("Server Connect");//PESocket里封裝好的方法,在控制臺(tái)輸出Debug.Log("Server Connect");}//收到數(shù)據(jù)protected override void OnReciveMsg(NetMsg msg){//PETool.LogMsg("Server Rsp:" + msg.text);Debug.Log("Server Rsp:" + msg.text);}//斷開(kāi)連接protected override void OnDisConnected(){//PETool.LogMsg("Server DisConnect");Debug.Log("Server DisConnect");}
}
GameStart
類(lèi),用于管理游戲?qū)ο蟮男袨檫壿嫛_@個(gè)腳本主要關(guān)注于建立與服務(wù)器的連接、配置日志記錄以及處理用戶輸入以發(fā)送消息給服務(wù)器。
using UnityEngine;
using Protocal;public class GameStart : MonoBehaviour
{PENet.PESocket<ClientSession, NetMsg> client = null;private void Start(){client = new PENet.PESocket<ClientSession, NetMsg>();client.StartAsClient(IPCfg.srvIP, IPCfg.srvPort);//啟動(dòng)客戶端//指定一個(gè)日志的接口,可以把PESocket里的日志通過(guò)unity控制臺(tái)打印;//(日志是否開(kāi)啟,日志的回調(diào)函數(shù)(內(nèi)容,日志的級(jí)別(?)))client.SetLog(true, (string msg, int lv) =>{switch (lv)//對(duì)不同的日志級(jí)別顯示不同的提示{case 0:msg = "Log:" + msg;Debug.Log(msg);break;case 1://警告msg = "Warn:" + msg;Debug.Log(msg);break;case 2://錯(cuò)誤msg = "Error:" + msg;Debug.Log(msg);break;case 3://普通信息msg = "Info:" + msg;Debug.Log(msg);break;}});}private void Update(){if (Input.GetKeyDown(KeyCode.Space)){client.session.SendMsg(new NetMsg { text = "Hello Unity" });}}
}