WebSocket使得客戶端和服務器之間的數(shù)據(jù)交換變得更加簡單,允許服務端主動向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數(shù)據(jù)傳輸。
WebSocket與http
其實從歷史上來講,websocket是為了克服http無法雙向通信而引入的,在通常的使用中,可以復用http的端口與功能,除此外,他們沒有其他的聯(lián)系,而是完全是獨立的協(xié)議,通常情況下,http是單向的web 服務,而websocket是全雙工的,服務器和客戶端可以實時的傳輸信息,在引用時他們可以在http服務器上同時部署,特別是在NodeJs中。
WebSocket與Socket?
那么websocket和socket是什么關系呢? 其實可以理解為websocket是在socket的基礎上實現(xiàn)的,其基于消息幀和TCP協(xié)議,而socket更通用,在編程中,可以選在tcp,udp,也需要自己控制數(shù)據(jù)流格式,每次的數(shù)據(jù)的長度都需要自己控制與讀取。
下邊記錄兩種Unity客戶端使用WebSocket的方法。
1.不使用插件的客戶端
引入System.Net.WebSockets;命名空間。
在使用過程中發(fā)現(xiàn)這種方法打包WebGl的的時候是存在問題的。
具體使用方法如下:
WebSocket 類 (System.Net.WebSockets) | Microsoft Learn
?Unity客戶端代碼:
using System;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class test4 : MonoBehaviour
{
private void Start()
{
WebSocket();
}
public async void WebSocket()
{
try
{
ClientWebSocket ws = new ClientWebSocket();
CancellationToken ct = new CancellationToken();
//添加header
//ws.Options.SetRequestHeader("X-Token", "eyJhbGciOiJIUzI1N");
Uri url = new Uri("ws://xxx.xxx.xxx.xx:18x/xxx/xxx");
await ws.ConnectAsync(url, ct);
await ws.SendAsync(new ArraySegment<byte>(Encoding.UTF8.GetBytes("hello")), WebSocketMessageType.Binary, true, ct); //發(fā)送數(shù)據(jù)
while (true)
{
var result = new byte[1024];
await ws.ReceiveAsync(new ArraySegment<byte>(result), new CancellationToken());//接受數(shù)據(jù)
var str = Encoding.UTF8.GetString(result, 0, result.Length);
Debug.Log(str);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
2.使用Best HTTP插件
這款插件不但支持WebSockets,還支持HTTP,Sockets等通信方式是一款不錯的插件。也支持打包Webgl文章來源:http://www.zghlxwxcb.cn/news/detail-489433.html
插件地址:
https://download.csdn.net/download/f402455894/87597949?spm=1001.2014.3001.5501文章來源地址http://www.zghlxwxcb.cn/news/detail-489433.html
客戶端代碼:
using UnityEngine;
using System;
using BestHTTP.WebSocket;
using Newtonsoft.Json;
public class GaoYaGuHuaLu : MonoBehaviour
{
string address = "ws://10.xxx.xx.193:1880/xxx";
WebSocket webSocket;
public GaoYaGuHuaLuEntity gaoYaGuHuaLu = new GaoYaGuHuaLuEntity();
private void Awake()
{
}
private void Start()
{
Init();
}
public void Init()
{
if (webSocket == null)
{
webSocket = new WebSocket(new Uri(address));
#if !UNITY_WEBGL
webSocket.StartPingThread = true;
#endif
// Subscribe to the WS events
webSocket.OnOpen += OnOpen;
webSocket.OnMessage += OnMessageRecv;
webSocket.OnBinary += OnBinaryRecv;
webSocket.OnClosed += OnClosed;
webSocket.OnError += OnError;
// Start connecting to the server
webSocket.Open();
}
}
public void Destroy()
{
if (webSocket != null)
{
webSocket.Close();
webSocket = null;
}
}
void OnOpen(WebSocket ws)
{
Debug.Log("OnOpen: ");
// webSocket.Send("我來啦");
}
void OnMessageRecv(WebSocket ws, string message)
{
Debug.LogFormat("OnMessageRecv: msg={0}", message);
}
void OnBinaryRecv(WebSocket ws, byte[] data)
{
Debug.LogFormat("OnBinaryRecv: len={0}", data.Length);
}
void OnClosed(WebSocket ws, UInt16 code, string message)
{
Debug.LogFormat("OnClosed: code={0}, msg={1}", code, message);
webSocket = null;
}
void OnError(WebSocket ws, string ex)
{
string errorMsg = string.Empty;
#if !UNITY_WEBGL || UNITY_EDITOR
if (ws.InternalRequest.Response != null)
{
errorMsg = string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
}
#endif
Debug.LogFormat("OnError: error occured: {0}\n", (ex != null ? ex : "Unknown Error " + errorMsg));
webSocket = null;
}
public void OnClose()
{
// 關閉連接
webSocket.Close(1000, "Bye!");
}
}
加上心跳檢測和斷線重連
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using BestHTTP;
using BestHTTP.WebSocket;
using BestHTTP.Examples;
public class ZGAndroidcCient : MonoBehaviour
{
// w ws://XXXX:7799
public string address = "ws://XXXX:7799";
WebSocket webSocket;
private bool lockReconnect = false;
private Coroutine _pingCor, _clientPing, _serverPing;
private void Start()
{
CreateWebSocket();
}
void CreateWebSocket()
{
try
{
webSocket = new WebSocket(new Uri(address));
#if !UNITY_WEBGL
webSocket.StartPingThread = true;
#endif
InitHandle();
webSocket.Open();
}
catch (Exception e)
{
Debug.Log("websocket連接異常:" + e.Message);
ReConnect();
}
}
private void Update()
{
Debug.Log(lockReconnect);
}
void InitHandle()
{
RemoveHandle();
webSocket.OnOpen += OnOpen;
webSocket.OnMessage += OnMessageReceived;
webSocket.OnClosed += OnClosed;
webSocket.OnError += OnError;
}
void RemoveHandle()
{
webSocket.OnOpen -= OnOpen;
webSocket.OnMessage -= OnMessageReceived;
webSocket.OnClosed -= OnClosed;
webSocket.OnError -= OnError;
}
void OnOpen(WebSocket ws)
{
Debug.Log("websocket連接成功");
webSocket.Send("一個客戶端連過來了");
if (_pingCor != null)
{
StopCoroutine(_pingCor);
_pingCor = null;
}
_pingCor = StartCoroutine(HeartPing());
// 心跳檢測重置
HeartCheck();
}
void OnMessageReceived(WebSocket ws, string message)
{
// 如果獲取到消息,心跳檢測重置
// 拿到任何消息都說明當前連接是正常的
HeartCheck();
Debug.Log(message);
}
void OnClosed(WebSocket ws, UInt16 code, string message)
{
Debug.LogFormat("OnClosed: code={0}, msg={1}", code, message);
webSocket = null;
ReConnect();
}
void OnError(WebSocket ws, string ex)
{
string errorMsg = string.Empty;
#if !UNITY_WEBGL || UNITY_EDITOR
if (ws.InternalRequest.Response != null)
{
errorMsg = string.Format("Status Code from Server: {0} and Message: {1}", ws.InternalRequest.Response.StatusCode, ws.InternalRequest.Response.Message);
}
#endif
Debug.LogFormat("OnError: error occured: {0}\n", (ex != null ? ex : "Unknown Error " + errorMsg));
webSocket = null;
ReConnect();
}
void ReConnect()
{
if (this.lockReconnect)
return;
this.lockReconnect = true;
StartCoroutine(SetReConnect());
}
private IEnumerator SetReConnect()
{
Debug.Log("正在重連websocket");
yield return new WaitForSeconds(5);
CreateWebSocket();
lockReconnect = false;
}
//心跳檢測
private void HeartCheck()
{
if (_clientPing != null)
{
StopCoroutine(_clientPing);
_clientPing = null;
}
if (_serverPing != null)
{
StopCoroutine(_serverPing);
_serverPing = null;
}
_clientPing = StartCoroutine(ClientPing());
}
// 這里發(fā)送一個心跳,后端收到后,返回一個心跳消息
// onmessage拿到返回的心跳就說明連接正常
private IEnumerator ClientPing()
{
yield return new WaitForSeconds(5);
WebSend("heartbeat");
_serverPing = StartCoroutine(ServerPing());
}
// 如果超過一定時間還沒重置,說明后端主動斷開了
// 如果onclose會執(zhí)行reconnect,我們執(zhí)行ws.close()就行了.如果直接執(zhí)行reconnect 會觸發(fā)onclose導致重連兩次
private IEnumerator ServerPing()
{
yield return new WaitForSeconds(5);
if (webSocket != null)
{
webSocket.Close();
}
}
//發(fā)送心跳
private IEnumerator HeartPing()
{
while (true)
{
yield return new WaitForSeconds(5);
this.WebSend("Heartbeat");
}
}
//向服務端發(fā)送信息
public void WebSend(string msg)
{
if (webSocket == null || string.IsNullOrEmpty(msg)) return;
if (webSocket.IsOpen)
{
webSocket.Send(msg);
}
}
public void OnClose()
{
// 關閉連接
webSocket.Close(1000, "Bye!");
}
}
到了這里,關于Unity中使用WebSocket (ws://)的方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!