using System.Collections;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using Protobuf;
|
using System.IO;
|
using System.Net;
|
using System.Net.Sockets;
|
using Google.Protobuf;
|
|
namespace KTGMGemClient
|
{
|
public class BaseSocket : MonoBehaviour
|
{
|
|
|
|
|
protected static int NET_HEADER_SIZE = 4;
|
|
//protected Dictionary<short, System.Type> packetReflections = new Dictionary<short, System.Type>();
|
|
protected Socket tcpSock;
|
|
string ip;
|
int port;
|
|
short remaining = 0;
|
short size = 0;
|
Opcode opcode;
|
|
|
protected virtual void OnConnected(bool connected)
|
{
|
|
}
|
protected virtual void OnData(Opcode opcode, IMessage msg)
|
{
|
|
}
|
|
|
|
public void Connect(string _host, int _port)
|
{
|
|
NetMapping.Init();
|
//IPHostEntry host = Dns.GetHostEntry(_host);
|
//endPoint = new IPEndPoint(host.AddressList[0], _port);
|
ip = _host;
|
port = _port;
|
//icount = 0;
|
|
|
|
//if(Defines.DebugNetWork)
|
// Debug.Log("StartConnect New Socket");
|
tcpSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
|
//_hasRecvBuf = false;
|
//! for next loop
|
//yield return 0;
|
|
// Setup our options:
|
// * NoDelay - don't use packet coalescing
|
// * DontLinger - don't keep sockets around once they've been disconnected
|
tcpSock.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, true);
|
tcpSock.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
|
|
|
//tcpSock.ReceiveTimeout = SOCKET_CONNECT_TIME_OUT * 1000;
|
//tcpSock.SendTimeout = SOCKET_SEND_TIME_OUT * 1000;
|
|
//if(Defines.DebugNetWork)
|
// Debug.Log("Net Connect:"+__ip+":"+__port);
|
tcpSock.BeginConnect(ip, port, OnEndConnect, tcpSock);
|
|
//float connectingTime = 0;
|
|
//while (!tcpSock.Connected && connectingTime <= SOCKET_CONNECT_TIME_OUT)
|
//{
|
// //if(Defines.DebugNetWork)
|
// // Debug.Log("NetConnecting: Time:"+_connectingTime);
|
// connectingTime += Time.deltaTime;
|
// yield return 0;
|
//}
|
|
}
|
|
private void OnEndConnect(System.IAsyncResult ar)
|
{
|
try
|
{
|
Socket client = (Socket)ar.AsyncState;
|
if (client != null)
|
{
|
client.EndConnect(ar);
|
}
|
OnConnected(true);
|
}
|
catch (System.Exception e)
|
{
|
Debug.Log(e);
|
OnConnected(false);
|
}
|
|
}
|
|
|
protected IEnumerator StartRecv()
|
{
|
//if(!_tcpSock.Connected)
|
// yield break;
|
|
CircleBuffer receiveBuffer = new CircleBuffer();
|
|
size = 0;
|
remaining = 0;
|
opcode = 0;
|
|
//float connectingTime = 0;
|
while (true)
|
{
|
yield return new WaitForEndOfFrame();
|
|
if (tcpSock == null || !tcpSock.Connected)
|
yield break;
|
|
|
|
|
|
// connectingTime += Time.deltaTime;
|
|
//DEBUG MODE DISABLE TRY CATCH...
|
// must have ,just in some socketException case
|
|
if (tcpSock.Poll(1, SelectMode.SelectRead))
|
{
|
// connectingTime = 0;
|
|
// try
|
// {
|
//byte[] buf = new byte[CircleBuffer.MAX_RECEIVE_BUFFER_SIZE];
|
|
int len = tcpSock.Receive(receiveBuffer.DataBuffer, receiveBuffer.Length, receiveBuffer.LeftSpaceSize, SocketFlags.None);
|
receiveBuffer.Enlarge(len);
|
// _totalBytesReceived += len;
|
|
// }
|
// catch (System.Exception)
|
// {
|
// Debug.LogWarning(e);
|
// yield break;
|
// }
|
|
OnReceive(receiveBuffer);
|
}
|
|
}
|
}
|
|
void OnReceive(CircleBuffer segment)
|
{
|
//Debug.Log("OnReceive: " );
|
//byte[] recvBuffer = segment.DataBuffer;
|
|
do
|
{
|
//const int offset = 0;
|
|
|
if (remaining == 0)
|
{
|
if (segment.Length < NET_HEADER_SIZE)
|
return;
|
//_option = recvBuffer[4];
|
remaining = size = bytesToShort(segment.DataBuffer, 0);//recvBuffer[offset] | recvBuffer[offset + 1] << 8;
|
opcode = (Opcode)bytesToShort(segment.DataBuffer, 2);//(OpcodeType)(recvBuffer[offset + 2] | recvBuffer[offset + 3] << 8);
|
|
}
|
|
if (remaining > 0 && remaining > segment.Length)
|
return;
|
|
// bool compressed = ((_option & PACKAGE_OPTION_MASK_COMPRESS) == PACKAGE_OPTION_MASK_COMPRESS);
|
//if(GameDefine.isDevelopBuild)
|
//#if UNITY_EDITOR
|
Debug.Log("rev:" + opcode.ToString() + " Size:" + size);
|
//#endif
|
//Stream stm = null;
|
|
|
IMessage message = DesrializePacket(opcode, segment, NET_HEADER_SIZE, size);
|
OnData(opcode, message);
|
// Stream stm = new MemoryStream(recvBuffer, NET_HEADER_SIZE, size - NET_HEADER_SIZE);
|
|
//if (compressed)
|
//{
|
// stm = new InflaterInputStream(stm);
|
//}
|
|
// Packet pkt = packetMgr.DeserializeGamePacket(_opcode, stm);
|
|
// packetMgr.HandleGamePacket(pkt);
|
|
//UIManager.I.ReceiveSocketType(pkt.OpCode);
|
|
// _hasRecvBuf = true;
|
segment.Shrink(size);
|
size = remaining = 0;
|
} while (segment.Length > 0);
|
|
//return ;
|
}
|
|
public void SendMsg(Opcode _opcode, IMessage _message)
|
{
|
|
byte[] databytes = _message.ToByteArray();
|
|
|
short send_size = (short)(databytes.Length + NET_HEADER_SIZE);//+ 2;
|
|
byte[] protobuf = new byte[send_size];
|
|
//bool compressed = ((_option & PACKAGE_OPTION_MASK_COMPRESS) == PACKAGE_OPTION_MASK_COMPRESS);
|
this.shortToBytes(send_size, ref protobuf, 0);
|
this.shortToBytes((short)_opcode, ref protobuf, 2);
|
System.Buffer.BlockCopy(databytes, 0, protobuf, NET_HEADER_SIZE, databytes.Length);
|
|
|
tcpSock.Send(protobuf);
|
|
//MemoryStream ms = new MemoryStream();
|
|
////FastBuf.BufferWriter bw = new FastBuf.BufferWriter(ms);
|
//ms.SetLength(0);
|
//send_pak.PacketObject.setSession(pid, key);
|
//packetMgr.SerializePacket(ms, send_pak.PacketObject);
|
|
//int size = (int)(ms.Length) + SEND_HEADER_SIZE;//+ 2;
|
|
//byte[] protobuf = new byte[size];
|
|
////bool compressed = ((_option & PACKAGE_OPTION_MASK_COMPRESS) == PACKAGE_OPTION_MASK_COMPRESS);
|
|
//MakePacketHeader(ref protobuf, size, (short)send_pak.OpCode, pid);
|
|
//ms.Position = 0;
|
//ms.Read(protobuf, SEND_HEADER_SIZE, (int)ms.Length);
|
|
//if (send_pak.OpCode != OpcodeType.C2S_LOGIN)
|
//{
|
// //byte[] encrypt_data = protobuf + SEND_HEADER_SIZE;
|
// RC4.Cipher(ref protobuf, SEND_HEADER_SIZE, rc4key + (icount).ToString());
|
//}
|
|
////if(Application.isEditor||Defines.DebugNetWork)
|
|
//_totalBytesSent += protobuf.Length;
|
//try
|
//{
|
// _tcpSock.Send(protobuf);
|
//}
|
//catch (System.Exception)
|
//{
|
// return false;
|
//}
|
//return true;
|
|
}
|
|
private void shortToBytes(short s, ref byte[] bytes, int offset)
|
{
|
bytes[offset + 0] = (byte)s;
|
bytes[offset + 1] = (byte)(s >> 8);
|
|
}
|
|
private short bytesToShort(byte[] bytes, int offset)
|
{
|
|
return (short)((bytes[offset] & 0xFF) | ((bytes[offset + 1] & 0xFF) << 8));
|
|
}
|
|
|
|
|
private IMessage DesrializePacket(Opcode opcode, CircleBuffer circleBuffer, int offset, int size)
|
{
|
//if (this._packetReflections.Count == 0)
|
//{
|
|
//}
|
System.Type optype;
|
|
if (NetMapping.packetReflections.TryGetValue(opcode, out optype))
|
{
|
if (null == optype)
|
{
|
return null;
|
}
|
Stream stream = new MemoryStream(circleBuffer.DataBuffer, offset, size - offset);
|
|
IMessage IMperson = System.Activator.CreateInstance(optype) as IMessage;
|
// Person2 p1 = new Person2();
|
return IMperson.Descriptor.Parser.ParseFrom(stream);
|
//return new Packet(opcode, msg);
|
|
}
|
return null;
|
}
|
|
/// <summary>
|
/// 关闭socket
|
/// </summary>
|
protected void Close()
|
{
|
if (tcpSock != null)
|
{
|
CommonDebugHelper.Debug("开始关闭Socket");
|
if (tcpSock.Connected) tcpSock.Shutdown(SocketShutdown.Both);
|
tcpSock.Close();
|
tcpSock = null;
|
|
StopCoroutine(StartRecv());
|
}
|
}
|
|
protected int reconnectTime = 0;//重连次数
|
/// <summary>
|
/// 断线重连
|
/// </summary>
|
/// <returns></returns>
|
IEnumerator Reconnect()
|
{
|
Close();
|
reconnectTime++;
|
Connect(ip, port);
|
if (!tcpSock.Connected)
|
{
|
if (reconnectTime <= 3)
|
{
|
yield return new WaitForSecondsRealtime(5);
|
StartCoroutine(Reconnect());
|
}
|
else
|
{
|
CommonDebugHelper.DebugError("重连超过3次,确定是断线了");
|
}
|
|
}
|
else
|
{
|
CommonDebugHelper.Debug("重连成功");
|
reconnectTime = 0;
|
StartCoroutine(StartRecv());
|
}
|
}
|
|
}
|
}
|