Unity版本: 5.3
使用語言: C#
寫在前面
ProtoBuf是Google公司推出的一種二進(jìn)制序列化工具榄棵,適用于數(shù)據(jù)的網(wǎng)絡(luò)傳輸蒙保。
基于Socket實(shí)現(xiàn)時(shí)時(shí)通信严拒,關(guān)于數(shù)據(jù)粘包的編碼和解碼處理是必不可少的焦人。
實(shí)現(xiàn)功能:
1.基于ProtoBuf序列化對(duì)象
2.使用Socket實(shí)現(xiàn)時(shí)時(shí)通信
3.數(shù)據(jù)包的編碼和解碼
2.Unity中使用Socket實(shí)現(xiàn)時(shí)時(shí)通信
通信應(yīng)該實(shí)現(xiàn)的功能:
- 1.服務(wù)器可以時(shí)時(shí)監(jiān)聽多個(gè)客戶端
- 2.服務(wù)器可以時(shí)時(shí)監(jiān)聽某一個(gè)客戶端消息
- 3.服務(wù)器可以時(shí)時(shí)給某一個(gè)客戶端發(fā)消息
首先我們需要定義一個(gè)客戶端對(duì)象
using System;
using System.Net.Sockets;
/// <summary>
/// 表示一個(gè)客戶端
/// </summary>
public class NetUserToken {
//連接客戶端的Socket
public Socket socket;
//用于存放接收數(shù)據(jù)
public byte[] buffer;
public NetUserToken()
{
buffer = new byte[1024];
}
/// <summary>
/// 接受消息
/// </summary>
/// <param name="data">Data.</param>
public void Receive(byte[] data)
{
UnityEngine.Debug.Log("接收到消息!");
}
/// <summary>
/// 發(fā)送消息
/// </summary>
/// <param name="data">Data.</param>
public void Send(byte[] data)
{
}
}
然后實(shí)現(xiàn)我們的服務(wù)器代碼
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System;
using System.Net.Sockets;
public class NetServer{
//單例腳本
public static readonly NetServer Instance = new NetServer();
//定義tcp服務(wù)器
private Socket server;
private int maxClient = 10;
//定義端口
private int port = 35353;
//用戶池
private Stack<NetUserToken> pools;
private NetServer()
{
//初始化socket
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, port));
}
//開啟服務(wù)器
public void Start()
{
server.Listen(maxClient);
UnityEngine.Debug.Log("Server OK!");
//實(shí)例化客戶端的用戶池
pools = new Stack<NetUserToken>(maxClient);
for(int i = 0; i < maxClient; i++)
{
NetUserToken usertoken = new NetUserToken();
pools.Push(usertoken);
}
//可以異步接受客戶端, BeginAccept函數(shù)的第一個(gè)參數(shù)是回調(diào)函數(shù)拯田,當(dāng)有客戶端連接的時(shí)候自動(dòng)調(diào)用
server.BeginAccept (AsyncAccept, null);
}
//回調(diào)函數(shù)历造, 有客戶端連接的時(shí)候會(huì)自動(dòng)調(diào)用此方法
private void AsyncAccept(IAsyncResult result)
{
try {
//結(jié)束監(jiān)聽,同時(shí)獲取到客戶端
Socket client = server.EndAccept(result);
UnityEngine.Debug.Log("有客戶端連接");
//來了一個(gè)客戶端
NetUserToken userToken = pools.Pop();
userToken.socket = client;
//客戶端連接之后,可以接受客戶端消息
BeginReceive(userToken);
//尾遞歸吭产,再次監(jiān)聽是否還有其他客戶端連入
server.BeginAccept(AsyncAccept, null);
} catch (Exception ex) {
UnityEngine.Debug.Log(ex.ToString());
}
}
//異步監(jiān)聽消息
private void BeginReceive(NetUserToken userToken)
{
try {
//異步方法
userToken.socket.BeginReceive(userToken.buffer, 0, userToken.buffer.Length, SocketFlags.None,
EndReceive, userToken);
} catch (Exception ex) {
UnityEngine.Debug.Log(ex.ToString());
}
}
//監(jiān)聽到消息之后調(diào)用的函數(shù)
private void EndReceive(IAsyncResult result)
{
try {
//取出客戶端
NetUserToken userToken = result.AsyncState as NetUserToken;
//獲取消息的長(zhǎng)度
int len = userToken.socket.EndReceive(result);
if(len > 0)
{
byte[] data = new byte[len];
Buffer.BlockCopy(userToken.buffer, 0, data, 0, len);
//用戶接受消息
userToken.Receive(data);
//尾遞歸侣监,再次監(jiān)聽客戶端消息
BeginReceive(userToken);
}
} catch (Exception ex) {
UnityEngine.Debug.Log(ex.ToString());
}
}
}
在Unity中開啟服務(wù)器,并使用C#控制臺(tái)模擬客戶端連接臣淤、發(fā)送消息操作橄霉。測(cè)試OK??,Unity中可以時(shí)時(shí)監(jiān)聽到消息邑蒋。
using UnityEngine;
using System.Collections;
public class CreateServer : MonoBehaviour {
void StartServer () {
NetServer.Instance.Start();
}
}
//C#控制臺(tái)工程
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
namespace Temp
{
class MainClass
{
public static void Main (string[] args)
{
TcpClient tc = new TcpClient();
IPEndPoint ip = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 35353);
tc.Connect(ip);
if(tc.Connected)
{
while(true)
{
string msg = Console.ReadLine();
byte[] result = Encoding.UTF8.GetBytes(msg);
tc.GetStream().Write(result, 0, result.Length);
}
}
Console.ReadLine();
}
}
}
寫在最后
#成功的道路沒有捷徑姓蜂,代碼這條路更是如此,唯有敲才是王道医吊。