作者:蟑螂惡霸
鏈接:https://www.zhihu.com/question/381711152/answer/3083699647
來源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
?
本文將從以下幾個方面來講解Unity客戶端網(wǎng)絡(luò)架構(gòu)的設(shè)計與實現(xiàn):
1.網(wǎng)絡(luò)通信協(xié)議的選擇
2.客戶端網(wǎng)絡(luò)框架的設(shè)計
3.網(wǎng)絡(luò)通信的實現(xiàn)
4.代碼實現(xiàn)
對啦!這里有個游戲開發(fā)交流小組里面聚集了一幫熱愛學(xué)習(xí)游戲的零基礎(chǔ)小白,也有一些正在從事游戲開發(fā)的技術(shù)大佬,歡迎你來交流學(xué)習(xí)。
一、網(wǎng)絡(luò)通信協(xié)議的選擇
網(wǎng)絡(luò)通信協(xié)議是實現(xiàn)客戶端與服務(wù)器之間通信的基礎(chǔ),目前常用的網(wǎng)絡(luò)通信協(xié)議有TCP和UDP兩種。
TCP協(xié)議是面向連接的協(xié)議,具有可靠性高、穩(wěn)定性好的特點,但是在傳輸大量數(shù)據(jù)時,效率較低。
UDP協(xié)議是無連接的協(xié)議,傳輸效率高,但是可靠性不如TCP。
在Unity客戶端網(wǎng)絡(luò)架構(gòu)的設(shè)計中,需要根據(jù)實際情況選擇合適的網(wǎng)絡(luò)通信協(xié)議。如果是對網(wǎng)絡(luò)傳輸?shù)姆€(wěn)定性和可靠性有要求的游戲,如MOBA游戲,就需要選擇TCP協(xié)議。如果是對網(wǎng)絡(luò)傳輸?shù)男视幸蟮挠螒?,如射擊游戲,就需要選擇UDP協(xié)議。
二、客戶端網(wǎng)絡(luò)框架的設(shè)計
在Unity客戶端網(wǎng)絡(luò)架構(gòu)的設(shè)計中,需要考慮以下幾個方面:
1.網(wǎng)絡(luò)連接的建立與斷開
2.消息的發(fā)送與接收
3.消息的封裝與解析
4.消息的處理與回調(diào)
網(wǎng)絡(luò)連接的建立與斷開
在客戶端網(wǎng)絡(luò)框架的設(shè)計中,需要實現(xiàn)網(wǎng)絡(luò)連接的建立與斷開。網(wǎng)絡(luò)連接的建立需要指定服務(wù)器的IP地址和端口號,通過Socket類建立TCP或UDP連接。網(wǎng)絡(luò)連接的斷開需要釋放Socket資源,關(guān)閉網(wǎng)絡(luò)連接。
消息的發(fā)送與接收
在客戶端網(wǎng)絡(luò)框架的設(shè)計中,需要實現(xiàn)消息的發(fā)送與接收。消息的發(fā)送需要將消息封裝成字節(jié)流,通過Socket類發(fā)送到服務(wù)器;消息的接收需要通過Socket類接收服務(wù)器發(fā)送的消息字節(jié)流,并將其解析成消息對象。
消息的封裝與解析
在客戶端網(wǎng)絡(luò)框架的設(shè)計中,需要實現(xiàn)消息的封裝與解析。消息的封裝需要將消息對象轉(zhuǎn)換成字節(jié)流,以便發(fā)送到服務(wù)器;消息的解析需要將服務(wù)器發(fā)送的字節(jié)流轉(zhuǎn)換成消息對象,以便在客戶端中進行處理。
消息的處理與回調(diào)
在客戶端網(wǎng)絡(luò)框架的設(shè)計中,需要實現(xiàn)消息的處理與回調(diào)。消息的處理需要根據(jù)消息類型進行相應(yīng)的處理,例如登錄消息需要進行賬號驗證;消息的回調(diào)需要在處理完消息后將處理結(jié)果返回給游戲邏輯層,以便進行相應(yīng)的處理。
三、網(wǎng)絡(luò)通信的實現(xiàn)
在Unity客戶端網(wǎng)絡(luò)架構(gòu)的實現(xiàn)中,需要使用Socket類進行網(wǎng)絡(luò)通信。Socket類是.NET Framework提供的用于網(wǎng)絡(luò)通信的基礎(chǔ)類,支持TCP和UDP兩種協(xié)議。
在使用Socket類進行網(wǎng)絡(luò)通信時,需要考慮以下幾個方面:
1.網(wǎng)絡(luò)連接的建立與斷開
2.消息的發(fā)送與接收
3.消息的封裝與解析
4.消息的處理與回調(diào)
網(wǎng)絡(luò)連接的建立與斷開
使用Socket類建立網(wǎng)絡(luò)連接的方法如下:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
使用Socket類斷開網(wǎng)絡(luò)連接的方法如下:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
消息的發(fā)送與接收
使用Socket類發(fā)送消息的方法如下:
byte[] bytes = message.ToBytes();
socket.Send(bytes);
使用Socket類接收消息的方法如下:
byte[] bytes = new byte[1024];
int length = socket.Receive(bytes);
Message message = Message.Parse(bytes, length);
消息的封裝與解析
消息的封裝需要將消息對象轉(zhuǎn)換成字節(jié)流,以便發(fā)送到服務(wù)器。消息的解析需要將服務(wù)器發(fā)送的字節(jié)流轉(zhuǎn)換成消息對象,以便在客戶端中進行處理。消息的封裝與解析可以通過序列化和反序列化來實現(xiàn)。
消息的處理與回調(diào)
消息的處理需要根據(jù)消息類型進行相應(yīng)的處理,例如登錄消息需要進行賬號驗證。消息的回調(diào)需要在處理完消息后將處理結(jié)果返回給游戲邏輯層,以便進行相應(yīng)的處理。
四、代碼實現(xiàn)
以下是一個簡單的Unity客戶端網(wǎng)絡(luò)框架的實現(xiàn),使用TCP協(xié)議進行網(wǎng)絡(luò)通信。該框架實現(xiàn)了網(wǎng)絡(luò)連接的建立與斷開、消息的發(fā)送與接收、消息的封裝與解析、消息的處理與回調(diào)等功能。
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
public class Client
{
private Socket socket;
private byte[] buffer;
public bool Connect(string ip, int port)
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(ip, port);
buffer = new byte[1024];
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
return true;
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
return false;
}
}
public void Disconnect()
{
if (socket != null && socket.Connected)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
public void Send(Message message)
{
byte[] bytes = message.ToBytes();
socket.Send(bytes);
}
private void ReceiveCallback(IAsyncResult ar)
{
try
{
int length = socket.EndReceive(ar);
if (length > 0)
{
Message message = Message.Parse(buffer, length);
OnMessageReceived(message);
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, null);
}
else
{
Disconnect();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Disconnect();
}
}
private void OnMessageReceived(Message message)
{
switch (message.Type)
{
case MessageType.Login:
LoginMessage loginMessage = (LoginMessage)message;
bool success = Login(loginMessage.Username, loginMessage.Password);
ResponseMessage responseMessage = new ResponseMessage(success);
Send(responseMessage);
break;
case MessageType.Move:
MoveMessage moveMessage = (MoveMessage)message;
Move(moveMessage.Direction);
break;
}
}
private bool Login(string username, string password)
{
// TODO: login logic
return true;
}
private void Move(int direction)
{
// TODO: move logic
}
}
public enum MessageType
{
Login,
Move
}
public abstract class Message
{
public MessageType Type { get; protected set; }
public abstract byte[] ToBytes();
public static Message Parse(byte[] bytes, int length)
{
MessageType type = (MessageType)BitConverter.ToInt32(bytes, 0);
switch (type)
{
case MessageType.Login:
return LoginMessage.Parse(bytes, length);
case MessageType.Move:
return MoveMessage.Parse(bytes, length);
default:
throw new ArgumentException("Invalid message type");
}
}
}
public class LoginMessage : Message
{
public string Username { get; private set; }
public string Password { get; private set; }
public LoginMessage(string username, string password)
{
Type = MessageType.Login;
Username = username;
Password = password;
}
public override byte[] ToBytes()
{
List<byte> bytes = new List<byte>();
bytes.AddRange(BitConverter.GetBytes((int)Type));
bytes.AddRange(BitConverter.GetBytes(Username.Length));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(Username));
bytes.AddRange(BitConverter.GetBytes(Password.Length));
bytes.AddRange(System.Text.Encoding.UTF8.GetBytes(Password));
return bytes.ToArray();
}
public static LoginMessage Parse(byte[] bytes, int length)
{
int offset = 4;
int usernameLength = BitConverter.ToInt32(bytes, offset);
offset += 4;
string username = System.Text.Encoding.UTF8.GetString(bytes, offset, usernameLength);
offset += usernameLength;
int passwordLength = BitConverter.ToInt32(bytes, offset);
offset += 4;
string password = System.Text.Encoding.UTF8.GetString(bytes, offset, passwordLength);
return new LoginMessage(username, password);
}
}
public class MoveMessage : Message
{
public int Direction { get; private set; }
public MoveMessage(int direction)
{
Type = MessageType.Move;
Direction = direction;
}
public override byte[] ToBytes()
{
List<byte> bytes = new List<byte>();
bytes.AddRange(BitConverter.GetBytes((int)Type));
bytes.AddRange(BitConverter.GetBytes(Direction));
return bytes.ToArray();
}
public static MoveMessage Parse(byte[] bytes, int length)
{
int offset = 4;
int direction = BitConverter.ToInt32(bytes, offset);
return new MoveMessage(direction);
}
}
public class ResponseMessage : Message
{
public bool Success { get; private set; }
public ResponseMessage(bool success)
{
Type = MessageType.Response;
Success = success;
}
public override byte[] ToBytes()
{
List<byte> bytes = new List<byte>();
bytes.AddRange(BitConverter.GetBytes((int)Type));
bytes.AddRange(BitConverter.GetBytes(Success));
return bytes.ToArray();
}
public static ResponseMessage Parse(byte[] bytes, int length)
{
int offset = 4;
bool success = BitConverter.ToBoolean(bytes, offset);
return new ResponseMessage(success);
}
}
以上代碼實現(xiàn)了一個簡單的Unity客戶端網(wǎng)絡(luò)框架,使用TCP協(xié)議進行網(wǎng)絡(luò)通信。在該框架中,客戶端可以建立和斷開網(wǎng)絡(luò)連接,發(fā)送和接收消息,并對不同類型的消息進行相應(yīng)的處理和回調(diào)。
作者:阿博的game圈
鏈接:https://www.zhihu.com/question/381711152/answer/2548719506
來源:知乎
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
?
目前能做大型MMORPG ARPG的主流游戲服務(wù)器框架編程語言有:
C++:網(wǎng)絡(luò)庫: libevent, libuv, iocp/epoll, 可靠的UDP網(wǎng)絡(luò)傳送kcp;
序列化與反序列化:protobuf;
協(xié)議加密解密: crypto;
http解析庫: curl;
數(shù)據(jù)庫: mysql, redis, mongodb;
多線程: pthread庫;
服務(wù)短尋路與導(dǎo)航: recastnavigation
行為決策樹: 具體的庫可以github搜索一下;
業(yè)務(wù)邏輯腳本開發(fā): Lua等輕量級嵌入式腳本語言
Java:
網(wǎng)絡(luò)庫: Netty, Mina;
序列化與反序列化:protobuf;
協(xié)議加密解密: crypto;
http解析庫: Java有很多這樣的jar包,可以自行找下;
數(shù)據(jù)庫: mysql, redis, mongodb;
多線程 Java Thread庫;
服務(wù)短尋路與導(dǎo)航: recastnavigation Java版本
行為決策樹: 也有Java版本;文章來源:http://www.zghlxwxcb.cn/news/detail-717882.html
C#和Go不太熟悉,大家可以根據(jù)上面的清單自行去找一下。游戲服務(wù)端的框架還是建議自己寫,自己粘合。服務(wù)器對穩(wěn)定性要求很好, 所以還是自己寫比較好。:文章來源地址http://www.zghlxwxcb.cn/news/detail-717882.html
到了這里,關(guān)于unity 聯(lián)網(wǎng)的游戲后端服務(wù)器框架和語言的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!