using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
namespace Engine.Net
{
/// 服务器类型
public enum ESockeType
{
/// 游戏服务器
Game = 0,
}
/// 服务器类型
public enum ESocketConnectType
{
/// 连接类型
TCP = 0,
UDP = 1,
}
/// 客户端socket对象
public class NetSocket
{
/// 连接对象
public Socket mSocket = null;
/// 接收数据的位置。
private int nRecvPos = 0;
/// 保存接受到的数据
private byte[] arrRecvBuff;
/// 接受到的消息
private Queue mQueueRecvMsg;
/// 消息日志对象
public NetMsgLog netMsgLog = new NetMsgLog();
/// 对发送的优化,增加处理:多线程调用SendMsg时的处理,BeginSend和EndSend的串行处理,增加发送缓冲区
private System.Object mSendLock = new System.Object();
/// 需要发送的内容
private byte[] mSendBuff;
/// 发送的长度
private int nSendBuffDataLen;
/// 表示已经调用了BeginSend,正在等待结束
private bool bSendPending = false;
/// 服务器类型
//public ESockeType socketType = ESockeType.Game;
/// 连接类型
public ESocketConnectType socketConnectType = ESocketConnectType.TCP;
/// 构造函数
public NetSocket(ESockeType type, ESocketConnectType connectType)
{
//socketType = type;
socketConnectType = connectType;
arrRecvBuff = new byte[NetMsg.MAX_MSG_LEN];
nRecvPos = 0;
mQueueRecvMsg = new Queue();
mSendBuff = new byte[NetMsg.MAX_MSG_LEN];
nSendBuffDataLen = 0;
}
#region 创建和断开连接
/// 创建Socket连接
public bool Connect(string strIp, int nPort)
{
//如果存在连接线断开
if (mSocket != null)
{
DoDisconnect(false);
}
try
{
if(socketConnectType == ESocketConnectType.TCP)
{
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
else if(socketConnectType == ESocketConnectType.UDP)
{
mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
CDebug.Log("Connect " + strIp + " "+nPort);
mSocket.BeginConnect(strIp, nPort, new AsyncCallback(ConnectCallback), mSocket);
//Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize);
mSocket.ReceiveBufferSize = 204800;
mSocket.SendBufferSize = 204800;
//Debug.Log(mSocket.ReceiveBufferSize + " " + mSocket.SendBufferSize);
}
catch (SocketException e)
{
SendDisconnectMsg(true);
CDebug.LogError(e.Message);
return false;
}
return true;
}
/// Socket连接完成
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
client.EndConnect(ar);
nRecvPos = 0;
if (!StartRecvMsg())
{
DoDisconnect();
}
SendConnectGSuccess();
}
catch (SocketException e)
{
CDebug.LogError(e.Message);
mSocket.Close();
mSocket = null;
}
}
/// Socket对象是否连接中
public bool IsConnected()
{
return (mSocket == null) ? false : mSocket.Connected;
}
/// 发送Socket连接失败的消息
private void SendDisconnectMsg(bool bReceiveDisconnMsg = true)
{
if (bReceiveDisconnMsg == true)
{
NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_FAIL);
//msg.arrData.WriteInt((int)socketType);
mQueueRecvMsg.Enqueue(msg);
}
}
/// 服务器连接成功
private void SendConnectGSuccess()
{
NetMsg msg = new NetMsg(NetCode.MSG_CONE_CONNECT_SUCCESS);
//msg.arrData.WriteInt((int)socketType); ;
mQueueRecvMsg.Enqueue(msg);
}
#endregion
#region 接受消息相关
/// 获得一个已经接受到的消息
public NetMsg RecvMsg()
{
if (mQueueRecvMsg.Count == 0)
return null;
NetMsg msg = null;
try
{
msg = mQueueRecvMsg.Dequeue();
}
catch
{ }
return msg;
}
/// 开始接受消息
private bool StartRecvMsg()
{
if (mSocket == null)
return false;
try
{
SocketError err;
mSocket.BeginReceive(arrRecvBuff, nRecvPos, arrRecvBuff.Length - nRecvPos, SocketFlags.None, out err, new AsyncCallback(RecvCallback), this);
}
catch
{
return false;
}
return true;
}
/// 消息接受完成
private void RecvCallback(IAsyncResult ar)
{
int nRecv = 0;
try
{
if (mSocket != null)
{
SocketError err;
nRecv = mSocket.EndReceive(ar, out err);
}
else
{
SendDisconnectMsg();
return;
}
}
catch (System.Exception e)
{
//出现异常
#if UNITY_EDITOR
CDebug.LogError("recv msg error "+ e.Message + e.StackTrace);
#endif
SendDisconnectMsg();
return;
}
//如果接受的字节数是0,断开连接
if (nRecv == 0)
{
DoDisconnect(true, "Common disconnect");
return;
}
//CDebug.Log("字节长度 " + nRecv);
//追加接受的到字节
nRecvPos += nRecv;
//循环读取接受到的全部消息内容
do
{
if (!IsConnected())
break;
NetMsg msg = null;
if (ParseMsg(ref arrRecvBuff, ref nRecvPos, ref msg))
{
//添加接收时序
UpdateMsgResSequence();
//解析成功吧消息添加到队列中
mQueueRecvMsg.Enqueue(msg);
//接受消息日志
netMsgLog.ResMessage(msg);
}
else
{
//解析失败
break;
}
} while (true);
//继续挂起接收消息
StartRecvMsg();
}
/// 解析消息
private bool ParseMsg(ref byte[] buff, ref int nLen, ref NetMsg msg)
{
//当前数据长度小于固定长度,返回失败
if (nLen < NetMsg.MIN_MSG_LEN)
return false;
msg = NetMsg.OnCreateNetMsg(buff);
//获得当前消息的长度
int nMsgSize = msg.arrData.ReadInt();
//判断消息长度是否合法
if (nMsgSize < NetBytes.INT32_LEN || nMsgSize > NetMsg.MAX_MSG_LEN)
{
//消息长度非法,断开连接
DoDisconnect(true, "Invalid msg len " + nMsgSize);
return false;
}
//如果当前消息不完整,失败
if (nLen < nMsgSize)
{
CDebug.Log("如果当前消息不完整 " + nLen + " " + nMsgSize);
return false;
}
if (!msg.ReadMessage(buff, nMsgSize))
{
RemoveBuff(ref buff, ref nLen, nMsgSize);
CDebug.Log("读取失败 " + nLen + " " + nMsgSize);
return false;
}
//清除该消息的缓冲区
RemoveBuff(ref buff, ref nLen, nMsgSize);
return true;
}
/// 清理消息buff
private void RemoveBuff(ref byte[] buff, ref int nLen, int nSize)
{
if (nSize <= nLen)
{
int nCopyLen = nLen - nSize;
for (int i = 0; i < nCopyLen; ++i)
{
buff[i] = buff[i + nSize];
}
nLen -= nSize;
}
}
/// 断开连接
public void DoDisconnect(bool bReceiveDisconnMsg = true, string strReason = null)
{
if (!IsConnected())
{
return;
}
if (!string.IsNullOrEmpty(strReason))
{
CDebug.LogError("Disconnect connection: " + strReason);
}
if (mSocket != null)
{
SendDisconnectMsg(bReceiveDisconnMsg);
CDebug.Log("尝试断开socket链接" + mSocket.Connected);
try
{
mSocket.Disconnect(true);
mSocket.Close();
}
catch
{
CDebug.LogError("DisConnected");
}
mSocket = null;
nRecvPos = 0;
}
}
/// 修改接受消息的消息时序
private void UpdateMsgResSequence()
{
//目前版本消息时序没有添加验证
}
#endregion
#region 发送消息相关
/// 发送消息
public bool SendMsg(NetMsg msg)
{
if (mSocket == null)
return false;
lock (mSendLock)
{
byte[] buff = null;
buff = msg.FastPackMsg();
if (buff == null)
return false;
//修改发送消息的消息时序
UpdateMsgSendSequence();
int nNewSendBuffDataLen = nSendBuffDataLen + buff.Length;
if (mSendBuff.Length < nNewSendBuffDataLen)
{
System.Array.Resize(ref mSendBuff, nNewSendBuffDataLen * 2);
}
System.Array.Copy(buff, 0, mSendBuff, nSendBuffDataLen, buff.Length);
nSendBuffDataLen += buff.Length;
//发送日志
netMsgLog.SendMessage(msg);
SendDataInBuffer_inLock();
}
return true;
}
/// 发送消息
private void SendDataInBuffer_inLock()
{
if (bSendPending)
return;
try
{
if (nSendBuffDataLen == 0)
return;
SocketError err;
mSocket.BeginSend(mSendBuff, 0, nSendBuffDataLen, SocketFlags.None, out err, SendCallback, this);
if (err != SocketError.Success && err != SocketError.WouldBlock)
{
DoDisconnect(true, "BeginSend error " + err.ToString());
return;
}
bSendPending = true;
}
catch (Exception e)
{
if (e is SocketException)
{
SocketException es = (SocketException)e;
if (es.SocketErrorCode == SocketError.Success
|| es.SocketErrorCode == SocketError.WouldBlock)
{
return;
}
}
DoDisconnect(true, "BeginSend excption: " + e.Message);
return;
}
}
/// 发送消息完成
private void SendCallback(IAsyncResult ar)
{
lock (mSendLock)
{
bSendPending = false;
if (mSocket == null)
return;
try
{
SocketError err;
int nSendLen = mSocket.EndSend(ar, out err);
if (nSendLen <= 0)
{
if (err != SocketError.Success && err != SocketError.WouldBlock)
{
DoDisconnect(true, "EndSend error " + err.ToString());
}
return;
}
RemoveBuff(ref mSendBuff, ref nSendBuffDataLen, nSendLen);
if (nSendBuffDataLen > 0)
{
SendDataInBuffer_inLock();
}
}
catch (Exception e)
{
//出现异常,可以判断一下是否需要断开连接
if (e is SocketException)
{
SocketException es = (SocketException)e;
if (es.SocketErrorCode == SocketError.Success
|| es.SocketErrorCode == SocketError.WouldBlock)
{
return;
}
}
DoDisconnect(true, "EndSend Exception " + e.Message);
}
}
}
/// 修改发送消息的消息时序
private void UpdateMsgSendSequence()
{
//目前版本消息时序没有添加验证
}
#endregion
}
}