目录
1.目的
1.1 学习一些:unity websockt一些知识
2.参考
2.1 unity websockt断线重连和心跳检测
- good:项目中使用到了,但是有点问题
本篇文章是基于BestHttp插件实现的websocket,大家可以搜索这个插件进行学习使用。
websocket是为了克服http无法双向通信而引入的,在通常的使用中,可以复用http的端口与功能,除此外,他们没有其他的联系,而是完全是独立的协议,通常情况下,http是单向的web 服务,而websocket是全双工的,服务器和客户端可以实时的传输信息,在引用时他们可以在http服务器上同时部署。
在弱网环境下,发送消息无法抵达接收端;抑或,断网到浏览器约定时限等一些异常情况都会触发onclose和onerror,所以理论上,我们只要在onclose和onerror时,重新创建长连接就可以。
思路
弱网、断连所导致重连都是被动的,而在一般的websocket连接中都是存在心跳机制的,客户端和服务端约定一个特定的心跳消息用于检测链路是否通信正常。
我们通过心跳机制,在客户端来检测链路的正常,在约定时间间隔内收不到心跳或者其他任何通信消息时,客户端进行主动重连。当连接成功时,开启心跳;在收到消息时,重置心跳并开启下一轮检测,所以我们只需要在onopen和onmessage中加入心跳检测就行。
code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP;
using BestHTTP.WebSocket;
using BestHTTP.Examples;
using System;
public class WebSocketModel : MonoBehaviour
{
string address;
WebSocket webSocket;
private bool lockReconnect = false;
private Coroutine _pingCor,_clientPing,_serverPing;
private void Start()
{
CreateWebSocket();
}
void CreateWebSocket()
{
try
{
webSocket = new WebSocket(new System.Uri("ws://8888ws"));//websocket访问地址
InitHandle();
webSocket.Open();
}
catch(Exception e)
{
Debug.Log("websocket连接异常:" + e.Message);
ReConnect();
}
}
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连接成功");
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.Log("websocket关闭," + message);
webSocket = null;
ReConnect();
}
void OnError(WebSocket ws, Exception ex)
{
if(ex!=null)
Debug.Log("websocket连接异常:" + ex.Message);
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());
}
// 这里发送一个心跳,后端收到后,返回一个心跳消息
// onmessage拿到返回的心跳就说明连接正常
private IEnumerator ClientPing()
{
yield return new WaitForSeconds(5);
Send("heartbeat");
_serverPing = StartCoroutine(ServerPing());
}
// 如果超过一定时间还没重置,说明后端主动断开了
// 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
private IEnumerator ServerPing()
{
yield return new WaitForSeconds(5);
webSocket.Close();
}
//发送心跳
private IEnumerator HeartPing()
{
while(true)
{
yield return new WaitForSeconds(5);
this.Send("heartbeat");
}
}
//向服务端发送信息
private void Send(string msg)
{
if (webSocket == null || string.IsNullOrEmpty(msg)) return;
if(webSocket.IsOpen)
{
webSocket.Send(msg);
}
}
}
3.注意
3.1 需要重连
4.操作
一定要再次重连,否则很难重连
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BestHTTP;
using BestHTTP.WebSocket;
using BestHTTP.Examples;
using System;
public class WebSocketModel : MonoBehaviour
{
string address;
WebSocket webSocket;
private bool lockReconnect = false;
private Coroutine _pingCor,_clientPing,_serverPing;
private void Start()
{
CreateWebSocket();
}
void CreateWebSocket()
{
try
{
webSocket = new WebSocket(new System.Uri("ws://8888ws"));//websocket访问地址
InitHandle();
webSocket.Open();
}
catch(Exception e)
{
Debug.Log("websocket连接异常:" + e.Message);
ReConnect();
}
}
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连接成功");
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.Log("websocket关闭," + message);
webSocket = null;
ReConnect();
}
void OnError(WebSocket ws, Exception ex)
{
if(ex!=null)
Debug.Log("websocket连接异常:" + ex.Message);
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());
}
// 这里发送一个心跳,后端收到后,返回一个心跳消息
// onmessage拿到返回的心跳就说明连接正常
private IEnumerator ClientPing()
{
yield return new WaitForSeconds(5);
Send("heartbeat");
_serverPing = StartCoroutine(ServerPing());
}
// 如果超过一定时间还没重置,说明后端主动断开了
// 如果onclose会执行reconnect,我们执行ws.close()就行了.如果直接执行reconnect 会触发onclose导致重连两次
private IEnumerator ServerPing()
{
yield return new WaitForSeconds(5);
webSocket.Close();
ReConnect();
}
//发送心跳
private IEnumerator HeartPing()
{
while(true)
{
yield return new WaitForSeconds(5);
this.Send("heartbeat");
}
}
//向服务端发送信息
private void Send(string msg)
{
if (webSocket == null || string.IsNullOrEmpty(msg)) return;
if(webSocket.IsOpen)
{
webSocket.Send(msg);
}
}
}