学习日记#07

学习日记#07


客户端网络管理

public string SecretKey {get;set;}
public string PublicKey = "abc1234";

private List<MsgBase> m_MsgList; // 存储所有解析完成的协议
private List<MagBase> m_UnityMsgList; // 存储所有要在unity处理的消息
private int m_MsgCount; // 消息计数器
private Thread m_MsgThread; // 消息线程
private Thread m_HeartThread; // 心跳线程
private long m_PingIntervale; // 心跳间隔

public delegate void ProtoListener(MsgBase msgBase); // 根据不同的协议监听不同的函数
private Dictionary<ProtocolEnum, ProtoListener> m_ProtoDic; // 存储不同协议所对应的不同的函数

private Queue<ByteArray> m_writeQueue; // 消息写入队列

private long lastPingTime; // 发送心跳包的时间
private long lastPongTime;// 接受心跳包的时间

public void  Connect(string ip, int port)
{
	if(m_Socket != null && m_Socket.Connected)
	{
		Debug.LogError("链接失败,已经链接过了");
		return;
	}
	InitState();
	m_Socket.NoDelay = true;
	m_Socket.BeginConnect(ip, port, ConnectCallback, m_Socket);// ????????????????
}

// 初始化状态
void InitState()
{
	m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
	byteArray = new ByteArray();
	m_MsgCount = 0;
	m_MsgList = new List<MsgBase>();
	m_UnityMsgList = new List<MsgBase>();
	m_ProtoDic = new Dictionary<ProtocolEnum, ProtoListener>();
	m_writeQueue = new Queue<ByteArray>();
	lastPingTime = GetTimeStamp();
	lastPongTime = GetTimeStam();
}

private int GetTimeStamp()
{
	TimeSpan timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
	return Convert.ToInt64(timeSpan.TotalSeconds);
}

void ConnectCallback(IAsyncResult asyncResult)// ??????????
{
	Debug.Log("已连接服务器");
	try
	{
		Socket socket = asyncResult.AsyncState as Socket;
		socket.EndConnect(asyncResult);// ????????关闭避免重复请求	
		m_MsgThread = new Thread(MsgThread);// 线程里面是一个函数
		m_MsgThread.IsBackground= true; // 在后台也 开启
		m_MsgThread.Start();// ?????????线程开启
		m_HeartThread = new Thread(PingThread);
		ProtoManager.CSSecret();// 协议管理器同一发送消息
		// 接受服务器的消息
		m_Socket.BeginReceive(bytrArray.Bytes, byteArray.WriteIdx, byteArray.Remain, 0, ReceiveCallback, socket);// ?????????/
		
	}
	catch(Exception)	
}

    try
    {
        Socket socket = asyncResult as Socket;
        int count = socket.EndReceive(asyncResult);

        if (count <= 0)
        {
            Close();
            return;
        }
        byteArray.WriteIdx += count;
        // 对接收到的消息进行处理
        OnReceiverData();
        if (byteArray.Remian < 8)
        {
            byteArray.CheckAndMoveBytes();
            byteArray.Resize(byteArray.Length * 2);
        }
        socket.BeginReceive(byteArray.Bytes, byteArray.WriteIdx, byteArray.Remian, 0,/*接受数据回调*/ReceiveCallback, socket
            );

    }
    catch (SocketException e)
    {
        Debug.LogError("接受数据回调异常" + e.ToString());
        Close();
    }


}
   void OnReceiverData()
   {
       if (byteArray.Length < 4 || byteArray.ReadIdx < 0)
       {
           Close();
       }
       int readIdx = byteArray.ReadIdx;
       byte[] bytes = byteArray.Bytes; 
       int bodyLength = BitConverter.ToInt32(bytes, readIdx);
       if (bodyLength + 4 > byteArray.Length)// 完整性验证 分包处理 
       {
           return;
       }
       // 对完整数据进行解析
       byteArray.ReadIdx += 4;

       // 解析协议名
       int nameCount = 0;
       ProtocolEnum protocol = ProtocolEnum.None;
       try
       {
           protocol = MsgBase.DecodeName(byteArray.Bytes, byteArray.ReadIdx, out nameCount);
       }
       catch(Exception e) 
       {
           Debug.Log(e.ToString());
           Close();
           return;

       }

       // 协议正确性判断
       if (protocol == ProtocolEnum.None)
       {
           Debug.Log("协议名错误");
           Close();
           return;
       }

       // 解析协议内容
       byteArray.ReadIdx += nameCount;
       int bodyCount = bodyLength - nameCount;
       MsgBase msgBase = null;
       try
       {
           msgBase = MsgBase.Decode(protocol, byteArray.Bytes, byteArray.ReadIdx, bodyCount);
       }
       catch(Exception e) 
       {
           Debug.LogError(e.ToString());
           Close();
           return;
       }

       if (msgBase == null)
       {
           Debug.Log("协议内容错误");
           return;
       }

       byteArray.ReadIdx += bodyCount;
       byteArray.CheckAndMoveBytes();
       // 上述 内容解析完成

       // 反射执行消息处理办法
       // 不要反射 
       // 消息类型 业务类型(Unity处理) 工具类型
       //MethodInfo methodInfo = typeof(MsgHandler).GetMethod(protocol.ToString());
       //object[] obj = { msgBase };
       //if (methodInfo != null)
       //{
       //    methodInfo.Invoke(null, obj);
       //}
       //else
       //{
       //    Debug.Log("消息处理办法不存在");
       //}
       // 将解析完成的协议进行处理
	lock (m_MsgList)
	{
		m_MsgList.Add(msgBase);
		m_MsgCount++;
	}


       if (byteArray.Length > 4) // 粘包
       {
           OnReceiverData();
       }
   }

void MsgThread()
{
	while(m_Socket != null && m_Socket.Connected)
	{
		Debug.Log("消息线程执行");
		if (m_MsgList.Count <= 0)
		{
			continue;
		}
		else
		{
			MsgBase msgBase = null;
			lock (m_MsgList)// 多线程中,写入原子消息
			{
				if (m_MsgList.Count > 0)
				{	
					msgBase = m_MsgList[0];
					m_MsgList.RemoveAt(0);
				}
			}
			if (msgBase != null)
			{
				if (msgBase is MsgPing)
				{
					lastPongTime = GetTimeStamp();
					Debug.Log("客户端接受心跳包");
					m_MsgCount--;
				}
				else
				{
					lock(m_UnityMsgList)
					{
						m_UnityMsgList.Add(msgBase);
					}
				}
			}
			else
			{
				break;
			}
		}
	}
}

private void PingThread()
{
	while(m_Socket != null && m_Socket.Connected)
	{
		long timeNow = GetTimeStamp();
		if (timeNow - lastPingTime > m_PingInterval)
		{
			MsgPing msgPing = new MsgPing();
			SendMessage(msgPing); // 例外的协议包发送
			lastPingTime = GetTimeStamp();
		}
		
		if (timeNow - lastPongTime > m_PingInterval * 4)// 服务器长时间未响应
		{
			Debug.Log("服务器长时间未响应");
			Close();
		}
	}
}

public void SendMessage(MsgBase msgBase)
{
	if (m_Socket == null || !m_Socket.Connected)
	{
    		return;
	}
	// 创建消息字节数组
	byte[] nameBytes = MsgBase.EncodeName(msgBase);
	byte[] bodyBytes = MsgBase.Encode(msgBase);
	int bodyLength = nameBytes.Length + bodyBytes.Length;
	byte[] headBytes = BitConverter.GetBytes(bodyLength);
	// 组装发送的字节数组
	byte[] sendBytes = new byte[headBytes.Length + nameBytes.Length + bodyBytes.Length];
	Array.Copy(headBytes, 0, sendBytes, 0, headBytes.Length); // 头部长度
	Array.Copy(nameBytes, 0, sendBytes, headBytes.Length, nameBytes.Length); // 消息名字节
	Array.Copy(bodyBytes, 0, sendBytes, headBytes.Length + nameBytes.Length, bodyBytes.Length); // 消息体字节

	ByteArray ba = new ByteArray(sendBytes);
	int count = 0;
	lock (m_writeQueue)
	{
		m_writeQueue.Enqueue(ba);
		count = m_writeQueue.Count;
	}
	if(count == 1)// ?????????????????????
	{
		m_Socket.BeginSend(sendBytes, 0 , sendBytes, 0, SendCallback, m_Socket);
	}
	
}

private void SendCallback(IAsyncResult asyncResult)
{
	try
	{
		Socket socket = asyncResult.AsyncState as Socket;
		if (socket == null || !socket.Connected())
		{
			return;
		}
		int count = socket.EndSend(asyncResult);
		// 判断发送是否完成
		ByteArray ba;
		lock (m_writeQueue)
		{
			ba = m_writeQueue.First();
		}
		ba.ReadIdx += count;
		if (ba.Length == 0) // 一条消息发送完整
		{
			lock (m_writeQueue)
			{
				m_writeQueue.Dequeue();
				if (m_writeQueue.Count > 0)
				{
					ba = m_writeQueue.First();	
				}
				else
				{
					ba = null;
				}
			}
		}
		if (ba != null)
		{
			socket.BeginSend(ba.Bytes, ba.ReadIdx, ba.Length, 0, SendCallback, m_Socket);// ??????????????????分包???????
		}
	}
}

public void  Close()
{
	if (m_Socket == null)
	{
		return;
	}
	SecretKey = "";
	m_Socket.Close();
	if (m_MsgThread != null && m_MsgThread.IsAlive)
	{
		m_MsgThread.Abort();
		m_MsgThread = null;
	}
	if (m_PingThread != null && m_PingThread.IsAlive)
	{
		m_PingThread.Abort();
		m_PingThread = null;
	}
	Debug.Log("关闭连接");
}

-------
public void MsgUpdate()
{
	if (m_Socket != null && m_Socket.Connected)
	{
		if (m_MsgCount == 0)
		{
			return ;
		}
		else
		{
			MsgBase magBase = null;
			lock (m_UnityMsgList)
			{
				if (m_UnityMsglist.Count > 0)
				{
					msgBase = m_UnityMsgList[0];
					m_UnityMsgList.RemoveAt(0);
					m_MsgCount--;
				}
			}
			if(magBase != null)
			{
				StatrProto(msgBase.ProtocolType, msgBase);
			}
		}
	}
}

    // 对协议进行监听
    public void AddProtoListener(ProtocolEnum protocol, ProtoListener protoListener)
    {
        if (!m_ProtoDic.ContainsKey(protocol))
        {
            m_ProtoDic[protocol] = protoListener;
        }
    }
    // 执行协议
    public void StartProto(ProtocolEnum protocol, MsgBase msgBase)
    {
        if (m_ProtoDic.ContainsKey(protocol))
        {
            m_ProtoDic[protocol](msgBase);
        }
    }

client -> socket -> connect -> ConenctCall(receive)->ReceiveCall(ReceiveCall)
当前客户端线程形成接受消息循环,
创建消息线程处理消息列表,工具逻辑自身处理,业务逻辑加入unity消息队列
创建心跳线程处理心跳包持续发送和活动客户端检查
注意多线程下的线程安全问题
msgUpdate开放给外部处理 Unity消息

算法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值