断线重连 心跳

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System;
using System.Text;


[XLua.LuaCallCSharp]
public class NetMgr : MonoBehaviour
{


    private EvtDefine.ConnSuccessHandle OnConnSuccessHandle;
    private EvtDefine.ConnFailedHandle OnConnFailedHandle;
    private EvtDefine.ConnCloseHandle OnConnCloseHandle;
    private EvtDefine.RecvHandle OnRecvHandle;
    private EvtDefine.SocketErrorHandle OnSocketErrorHandle;


    private Socket client;
    private IPEndPoint address;
    private bool isAutoConn = true; //是否开启自动重连接
    private bool isHeart = true;    //开启心跳
    private int reConnCount = 0;    //重连次数
    private int curConnCount = 0;   //当前连接次数


    /// <summary>
    /// 是否已连接
    /// </summary>
    public bool isConn
    {
        get
        {
            if (client == null)
                return false;
            return client.Connected;
        }
    }


    /// <summary>
    /// 连接
    /// </summary>
    /// <param name="ip"></param>
    /// <param name="port"></param>
    /// <param name="rCC">重连次数</param>
    public void Connect(string ip, int port, int rCC,
        Action connSuccessAcion,
        Action<string> connFailedHandle,
        Action<string> connCloseHandle,
        Action<int, string> recvHandle,
        Action<int, string> socketErrorHandle)
    {
        IPAddress ipAddress = IPAddress.Parse(ip);
        address = new IPEndPoint(ipAddress, port);
        reConnCount = rCC;
        curConnCount = 0;


        if (connSuccessAcion != null)
            OnConnSuccessHandle = new EvtDefine.ConnSuccessHandle(connSuccessAcion);


        if (connFailedHandle != null)
            OnConnFailedHandle = new EvtDefine.ConnFailedHandle(connFailedHandle);


        if (connCloseHandle != null)
            OnConnCloseHandle = new EvtDefine.ConnCloseHandle(connCloseHandle);


        if (recvHandle != null)
            OnRecvHandle = new EvtDefine.RecvHandle(recvHandle);


        if (socketErrorHandle != null)
            OnSocketErrorHandle = new EvtDefine.SocketErrorHandle(socketErrorHandle);


        StartCoroutine(AutoConn());
        StartCoroutine(HeartEnumerator());
    }




    #region 事件回调
    /// <summary>
    /// 接收回调
    /// </summary>
    /// <param name="msgType"></param>
    /// <param name="msg"></param>
    public void CallRecv(int msgType, string msg)
    {
        if (OnRecvHandle != null)
        {
            OnRecvHandle(msgType, msg);
        }
    }


    /// <summary>
    /// 异常回调
    /// </summary>
    /// <param name="msgType"></param>
    /// <param name="err"></param>
    public void CallSocketError(int msgType, string err)
    {
        if (OnSocketErrorHandle != null)
        {
            OnSocketErrorHandle(msgType, err);
        }
    }


    /// <summary>
    /// 断线
    /// </summary>
    /// <param name="msg"></param>
    public void CallConnClose(string msg)
    {
        if (OnConnCloseHandle != null)
        {
            OnConnCloseHandle(msg);
        }
    }


    //连接成功
    private void CallConnSuccess()
    {
        if (OnConnSuccessHandle != null)
        {
            OnConnSuccessHandle();
        }
    }


    //连接失败
    private void CallConnFailed(Exception ex)
    {
        if (OnConnFailedHandle != null)
        {
            OnConnFailedHandle(ex.Message);
        }
    }


    #endregion


    /// <summary>
    /// 发送心跳
    /// </summary>
    /// <returns></returns>
    private IEnumerator HeartEnumerator()
    {
        while (isHeart && isConn)
        {
            Send(1, "heart");
            yield return new WaitForSeconds(50);
        }
    }


    /// <summary>
    /// 自动重连
    /// </summary>
    /// <returns></returns>
    private IEnumerator AutoConn()
    {
        while (isAutoConn)
        {
            if (isConn == false && curConnCount <= reConnCount)
            {
                //Tools.ShowTip("正在连接...",false);
                Connection();
                curConnCount++;
            }
            yield return new WaitForSeconds(1);
        }
    }


    /// <summary>
    /// 连接
    /// </summary>
    /// <returns></returns>
    private void Connection()
    {
        try
        {
            if (isConn == false)
            {
                if (address == null)
                {
                    Debug.LogError("网络未初始化");
                    return;
                }
                client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                client.Connect(address);
                //重置连接次数
                curConnCount = 0;
                CallConnSuccess();
                ReceiveDataHandle recv = new ReceiveDataHandle(client);
                recv.client.BeginReceive(recv.Bytes, recv.StartPos, recv.EndPos, SocketFlags.None, ReceiveCallback, recv);
            }
        }
        catch (Exception ex)
        {
            CallConnFailed(ex);
        }
    }


    private void Send(byte[] _bytes)
    {
        if (client == null || client.Connected == false)
        {
            Debug.Log("未连接");
            //Tools.ShowTip("未连接");
            return;
        }
        client.BeginSend(_bytes, 0, _bytes.Length, SocketFlags.None, SendCallback, null);
    }


    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            client.EndSend(ar);
        }
        catch (Exception ex)
        {
            Debug.LogError(string.Format("发送消息失败:{0}", ex.Message));
        }
    }


    public void Send(int cmd, string str)
    {
        int headerLen = ReceiveDataHandle.HeadLength;


        //包内容
        byte[] byteContent = Encoding.UTF8.GetBytes(str);
        int contentLen = byteContent.Length;


        //报文长度
        byte[] header = new byte[headerLen];
        ushort len = (ushort)(contentLen);
        header = BitConverter.GetBytes(len);


        byte[] msgType = new byte[headerLen];
        msgType = BitConverter.GetBytes((ushort)cmd);


        //消息包
        byte[] msgPacket = new byte[len + headerLen + headerLen];
        header.CopyTo(msgPacket, 0);
        msgType.CopyTo(msgPacket, 2);
        byteContent.CopyTo(msgPacket, 4);
        //发送
        Send(msgPacket);
    }


    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            ReceiveDataHandle recv = (ReceiveDataHandle)ar.AsyncState;
            int recvCount = recv.client.EndReceive(ar);
            if (recvCount < ReceiveDataHandle.HeadLength + ReceiveDataHandle.MsgType)   //不够解析包头和协议类型
            {
                //断开客户端
                recv.CloseConn();
                CallConnClose(string.Empty);
                Debug.Log(string.Format("连接已断开"));
                return;
            }
            recv.recvDataLen = recvCount;
            ProcessData(recv);
        }
        catch (Exception ex)
        {
            CallSocketError(1, ex.Message);
        }
    }


    private void ProcessData(ReceiveDataHandle recv)
    {
        try
        {
            //获取报文长度
            int bodySize = recv.GetMsgLen();
            if (bodySize < 0)   //不合法数据
            {
                //断开客户端
                //recv.client.Close();
                recv.CloseConn();
                CallConnClose(string.Empty);
                return;
            }


            //获取应该要收到的字节
            int packLen = bodySize + ReceiveDataHandle.HeadLength + ReceiveDataHandle.MsgType - recv.CurBufferSize;
            if (recv.recvDataLen == packLen)
            {
                //完整包
                string msg = System.Text.Encoding.UTF8.GetString(recv.Bytes, 4, bodySize);
                CallRecv(recv.GetMsgType(), msg);
                Debug.Log(string.Format("收到消息:{0}", msg));
                recv.InitBuffer();
                recv.client.BeginReceive(recv.Bytes, recv.StartPos, recv.EndPos, SocketFlags.None, new AsyncCallback(ReceiveCallback), recv);
            }
            else
            {
                if (recv.recvDataLen < packLen)
                {
                    Debug.Log("不够继续接收");
                    //不够
                    recv.CurBufferSize += recv.recvDataLen;
                    recv.StartPos += recv.recvDataLen;
                    //继续接收
                    recv.client.BeginReceive(recv.Bytes, recv.StartPos, ReceiveDataHandle.BufferMaxSize - recv.CurBufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), recv);
                }
                else if (recv.recvDataLen > packLen)
                {
                    Debug.Log("多余的包,分包");
                    //完整包
                    string msg = System.Text.Encoding.UTF8.GetString(recv.Bytes, 4, bodySize);
                    CallRecv(recv.GetMsgType(), msg);
                    Debug.Log(string.Format("收到消息:{0}", msg));


                    //多余的字节
                    int temp2 = recv.recvDataLen - packLen;
                    byte[] tempByte = new byte[ReceiveDataHandle.BufferMaxSize];
                    Array.Copy(recv.Bytes, packLen, tempByte, 0, temp2);
                    recv.Bytes = tempByte;
                    recv.recvDataLen = temp2;
                    if (temp2 < ReceiveDataHandle.HeadLength + ReceiveDataHandle.MsgType)
                    {
                        //继续接收
                        recv.CurBufferSize = temp2;
                        recv.StartPos = temp2;
                        recv.client.BeginReceive(recv.Bytes, recv.StartPos, ReceiveDataHandle.BufferMaxSize - recv.CurBufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), recv);
                        return;
                    }
                    ProcessData(recv);
                }
            }
        }
        catch (Exception ex)
        {
            //断开客户端
            recv.CloseConn();
            CallConnClose(string.Empty);
            Debug.LogError(string.Format("连接已断开,处理服务端数据,出现异常", ex.Message));
            return;
        }
    }


    /// <summary>
    /// 关闭连接
    /// </summary>
    private void DisConnection()
    {
        isAutoConn = false;
        StopCoroutine(AutoConn());
        if (client == null || !client.Connected)
        {
            return;
        }
        client.Shutdown(SocketShutdown.Both);
        client.Close();
        Debug.Log("连接已挂断");
    }


    private void OnDestroy()
    {
        OnConnSuccessHandle = null;
        OnConnFailedHandle = null;
        OnConnCloseHandle = null;
        OnRecvHandle = null;
        OnSocketErrorHandle = null;
        DisConnection();
    }


}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
RabbitMQ使用心跳机制来检测客户端与服务器之间的连接状态。当客户端与服务器之间的网络连接断开时,RabbitMQ会通过心跳消息检测到,并且会触发掉线重连的机制。 在 RabbitMQ 中,默认的心跳超时时间为60秒。当客户端在60秒内没有向服务器发送任何消息时,服务器会发送一个心跳消息给客户端,以确认连接是否正常。如果客户端在一定时间内没有收到心跳消息,就会认为与服务器之间的连接已经断开,并触发掉线重连操作。 掉线重连的实现可以通过 RabbitMQ 客户端提供的机制来完成。不同的客户端库可能会有不同的具体实现方式,但一般可以通过以下步骤来实现掉线重连: 1. 监听连接状态:通过注册连接状态的回调函数或者事件处理函数,来监听与 RabbitMQ 服务器之间的连接状态变化。 2. 检测到掉线:当连接状态变为断开状态时,即可判断为掉线。可以通过捕获异常、检查错误码或者其他方式来确认掉线状态。 3. 重连操作:在掉线后,需要重新建立与 RabbitMQ 服务器的连接。可以根据具体需求选择不同的重连策略,比如指数退避重连、固定时间间隔重连等。 4. 恢复消息传递:在重新建立连接后,需要重新订阅队列、重新发送未确认的消息等,以确保消息的可靠传递。 需要注意的是,掉线重连操作可能会对系统的性能产生一定的影响,所以在实际应用中需要根据具体情况权衡是否需要开启掉线重连功能。另外,还应该考虑网络稳定性、服务器负载等因素来优化掉线重连的策略。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值