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 packetReflections = new Dictionary(); 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; } /// /// 关闭socket /// 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;//重连次数 /// /// 断线重连 /// /// 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()); } } } }