TCPConn.cs 9.17 KB
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;


namespace FObjBase
{
    public delegate bool ParsePacketHandler(byte[] packet, IFConn conn);
    public class TCPConn:IFConn
    {
        static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        public bool HasCRC = false;

        TimeSpan Heartbeat_Interval = TimeSpan.FromSeconds(3);         // heartbeat包发送间隔时间,3秒
        TimeSpan Silent_Time = TimeSpan.FromSeconds(10);                // 单位ms没有收到任何东西的时间,10秒
        const int MAX_BUFFER = 20 * 0x4000;//20个大包, 大包的尺寸在FObjSys 定义
        protected List<byte> in_buffer = new List<byte>(MAX_BUFFER);
        protected List<byte> out_buffer = new List<byte>(MAX_BUFFER);
        protected DateTime comm_time;
        protected DateTime heartbeat_time = DateTime.Now;

        public ParsePacketHandler ParsePacket = null;

        public Socket sock;
      
        protected bool first_poll=true;

        public TCPConn() 
        {
        
        }
        public TCPConn(Socket sock) 
        {
            this.sock = sock;
        }

        public virtual int SendPacket(byte[] buffer)
        {
            int len = buffer.Length;
            out_buffer.AddRange(buffer);
            return len;
        }

        protected virtual int GetRecvInfoPacket()   // return length of the packet
        {
            int len = in_buffer.Count();
            if (len < 2) return 0;
            byte[] bs = new byte[2];

            int plen = BitConverter.ToUInt16(in_buffer.GetRange(0, 2).ToArray(), 0);

            if (plen > 0x4000 * 2)
            {
                //包太大,不正常!!!!!!
                //断开重新连接
                logger.Error("TCPConn GetRecvInfoPacket 包太大,不正常, 断开重新连接");
                sock.Close();

                return -1;
            }

            if (len < plen)
            {
                return 0;
            }

            if (HasCRC) //TODO
            {
                UInt16 crc = Misc.CRC.CRC16(in_buffer, 0, plen - 2);
                int packet_crc_idx = plen - 2;
                UInt16 packet_crc = BitConverter.ToUInt16(in_buffer.GetRange(packet_crc_idx, 2).ToArray(), 0);
                if (crc != packet_crc)
                {
                    logger.Error("TCPConn GetRecvInfoPacket CRC != packet_crc 断开重新连接");
                    //断开重新连接
                    sock.Close();
                    return -1;
                }
            }



            if (len >= plen)
            {
                return plen;
            }
            return 0;
        }
 
        protected virtual bool Parse_Packet(int len)
        {
            byte[] packet = in_buffer.GetRange(0, len).ToArray();
            in_buffer.RemoveRange(0, len);
            return ParsePacket(packet, this);
        }
        

        void Send_HeartBeat()
        {
            byte[] buf = new byte[2];
            buf[0] = 0x02;
            buf[1] = 0x00;
            SendPacket(buf);
            return;
        }
        int Send_Poll2() 
        {
            if (out_buffer.Count() == 0)
            {
                if ((DateTime.Now - heartbeat_time) > Heartbeat_Interval)
                {
                    Send_HeartBeat();//是时候把心跳包放入发送缓存!!!
                }
                else
                    return 0;
            }

            heartbeat_time = DateTime.Now;
            return Send_Poll();
        }
        int Send_Poll()
        {
            int cnt_total = 0;
            if (out_buffer.Count() == 0)//没数据,直接返回
                return 0;

            while (out_buffer.Count() > 0)//只有有数据发送,且能发送,没有 block, 就会一直循环
            {
                int cnt;
                try
                {
                    cnt = sock.Send(out_buffer.ToArray());
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    if (e.SocketErrorCode == SocketError.WouldBlock)//当前发不了,退出循环,等下次!!!!
                        break;
                    return -1;//异常,断开连接!!!
                }

                if (cnt > 0)
                {
                    out_buffer.RemoveRange(0, cnt);//发送成功,删除!!!
                    cnt_total+=cnt;
                }
                else
                {
                    break;
                }
            }
            return cnt_total;//返回总发送量
        }
        
        int Receive_Poll()
        {
            int reclen_total = 0;
            while (true)
            {
                int reclen;
                try
                {
                    reclen = sock.Available;
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    //FDEBUG.Debug.LogMessage(this, 10, "Receive_Poll e=" + e.ToString());
                    if (reclen_total == 0)
                    {
                        logger.Debug(e,"TCPConn Receive_Poll 什么都收不到");
                        return -1;
                    }
                    else
                        return reclen_total;
                }

                if (reclen == 0)
                    return reclen_total;

                byte[] buf = new byte[reclen];
                try
                {
                    reclen = sock.Receive(buf);
                }
                catch (System.Net.Sockets.SocketException e)
                {
                    //FDEBUG.Debug.LogMessage(this, 10, "Receive_Poll e=" + e.ToString());
                    if (reclen_total == 0)
                    {
                        logger.Debug(e, "TCPConn Receive_Poll 什么都收不到");
                        return -1;
                    }
                    else
                        return reclen_total;
                }
                if (reclen > 0)
                {
                    in_buffer.AddRange(buf);
                    reclen_total += reclen;

                    comm_time = DateTime.Now;
                }
            }
        }
        protected void Init() 
        {
            if (first_poll)
            {
                comm_time = DateTime.Now;
                heartbeat_time = DateTime.Now;
                first_poll = false;
            }
        }
        public virtual int OnPoll()
        {
            int ret=0;
            Init();

            int reclen = Receive_Poll();
            if (reclen < 0)
            {
                ret = -1;
                goto end;
            }
            else if (reclen == 0)
            {
                if ((DateTime.Now-comm_time) > Silent_Time)
                {
                    logger.Error("TCPConn OnPoll 长时间没收到任何数据 断开连接");

                    ret = -2;
                    goto end;
                }
            }
            else
            {
                while (true)
                {
                    int packet_len = GetRecvInfoPacket();
                    if (packet_len > 0)
                    {
                        Parse_Packet(packet_len);
                    }
                    else if (packet_len == 0)
                    {
                        break;
                    }
                    else 
                    {
                        //异常
                        ret = -1;
                        goto end;
                    }
                }
            }
            int sendlen = Send_Poll2();

            if (sendlen < 0)
            {
                ret = -1;
                goto end;
            }
        end:
            if (ret != 0)
            {
                //连接断开,清空接收缓存区
                logger.Error("TCPConn OnPoll 连接断开,清空接收缓存区");

                in_buffer.Clear();
                out_buffer.Clear();
                Enable = false;
            }
            return ret;
        }

        #region IFConn 成员

        public ConnectHandler ConnectAction
        {
            get;
            set;
        }
        protected bool isconnected = false;
        public virtual bool IsConnected
        {
            get {
                return isconnected;
            }
            set {
                if (isconnected != value) 
                {
                    isconnected = value;
                    ConnectAction(this);
                }
            }
        }


        protected bool enable=false;
        public bool Enable
        {
            get
            {
                return enable;
            }
            set
            {
                enable = value;
                if (enable == false) 
                {
                    Stop();
                }
            }
        }
        protected virtual void Stop() 
        {
            if (sock != null)
                sock.Close();
            IsConnected = false;
        } 
        #endregion

        #region IFConn 成员


        public uint TranID
        {
            get;
            set;
        }

        #endregion
    }
}