TCPConn.cs 9.47 KB
Newer Older
潘栩锋's avatar
潘栩锋 committed
1 2 3 4 5 6 7 8 9 10 11 12 13
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
    {
潘栩锋's avatar
潘栩锋 committed
14
        static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
潘栩锋's avatar
潘栩锋 committed
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
        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)
        {
42 43 44 45 46 47 48 49
            lock (out_buffer)
            {
                int len = buffer.Length;

                out_buffer.AddRange(buffer);

                return len;
            }
潘栩锋's avatar
潘栩锋 committed
50
        }
潘栩锋's avatar
潘栩锋 committed
51

潘栩锋's avatar
潘栩锋 committed
52 53
        protected virtual int GetRecvInfoPacket()   // return length of the packet
        {
潘栩锋's avatar
潘栩锋 committed
54
            int len = in_buffer.Count();
潘栩锋's avatar
潘栩锋 committed
55 56 57
            if (len < 2) return 0;
            byte[] bs = new byte[2];

潘栩锋's avatar
潘栩锋 committed
58 59 60 61
            int plen = BitConverter.ToUInt16(in_buffer.GetRange(0, 2).ToArray(), 0);

            if (plen > 0x4000 * 2)
            {
潘栩锋's avatar
潘栩锋 committed
62 63
                //包太大,不正常!!!!!!
                //断开重新连接
潘栩锋's avatar
潘栩锋 committed
64
                logger.Error("TCPConn GetRecvInfoPacket 包太大,不正常, 断开重新连接");
潘栩锋's avatar
潘栩锋 committed
65
                sock.Close();
潘栩锋's avatar
潘栩锋 committed
66

潘栩锋's avatar
潘栩锋 committed
67 68 69 70 71 72 73 74 75 76
                return -1;
            }

            if (len < plen)
            {
                return 0;
            }

            if (HasCRC) //TODO
            {
潘栩锋's avatar
潘栩锋 committed
77 78
                UInt16 crc = Misc.CRC.CRC16(in_buffer, 0, plen - 2);
                int packet_crc_idx = plen - 2;
潘栩锋's avatar
潘栩锋 committed
79 80 81
                UInt16 packet_crc = BitConverter.ToUInt16(in_buffer.GetRange(packet_crc_idx, 2).ToArray(), 0);
                if (crc != packet_crc)
                {
潘栩锋's avatar
潘栩锋 committed
82
                    logger.Error("TCPConn GetRecvInfoPacket CRC != packet_crc 断开重新连接");
潘栩锋's avatar
潘栩锋 committed
83 84 85 86 87 88 89 90 91 92 93 94 95 96
                    //断开重新连接
                    sock.Close();
                    return -1;
                }
            }



            if (len >= plen)
            {
                return plen;
            }
            return 0;
        }
潘栩锋's avatar
潘栩锋 committed
97 98
 
        protected virtual bool Parse_Packet(int len)
潘栩锋's avatar
潘栩锋 committed
99
        {
潘栩锋's avatar
潘栩锋 committed
100 101
            byte[] packet = in_buffer.GetRange(0, len).ToArray();
            in_buffer.RemoveRange(0, len);
潘栩锋's avatar
潘栩锋 committed
102 103
            return ParsePacket(packet, this);
        }
潘栩锋's avatar
潘栩锋 committed
104
        
潘栩锋's avatar
潘栩锋 committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119

        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)
                {
潘栩锋's avatar
潘栩锋 committed
120
                    Send_HeartBeat();//是时候把心跳包放入发送缓存!!!
潘栩锋's avatar
潘栩锋 committed
121 122 123 124 125 126 127 128 129 130
                }
                else
                    return 0;
            }

            heartbeat_time = DateTime.Now;
            return Send_Poll();
        }
        int Send_Poll()
        {
131
            
潘栩锋's avatar
潘栩锋 committed
132
            if (out_buffer.Count() == 0)//没数据,直接返回
潘栩锋's avatar
潘栩锋 committed
133
                return 0;
134 135 136
            lock (out_buffer) {
                int cnt_total = 0;
                while (out_buffer.Count() > 0)//只有有数据发送,且能发送,没有 block, 就会一直循环
潘栩锋's avatar
潘栩锋 committed
137
                {
138 139 140 141 142 143 144 145 146 147 148
                    int cnt;
                    try
                    {
                        cnt = sock.Send(out_buffer.ToArray());
                    }
                    catch (System.Net.Sockets.SocketException e)
                    {
                        if (e.SocketErrorCode == SocketError.WouldBlock)//当前发不了,退出循环,等下次!!!!
                            break;
                        return -1;//异常,断开连接!!!
                    }
潘栩锋's avatar
潘栩锋 committed
149

150 151 152 153 154 155 156 157 158
                    if (cnt > 0)
                    {
                        out_buffer.RemoveRange(0, cnt);//发送成功,删除!!!
                        cnt_total+=cnt;
                    }
                    else
                    {
                        break;
                    }
潘栩锋's avatar
潘栩锋 committed
159
                }
160
                return cnt_total;//返回总发送量
潘栩锋's avatar
潘栩锋 committed
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
            }
        }
        
        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)
潘栩锋's avatar
潘栩锋 committed
178
                    {
潘栩锋's avatar
潘栩锋 committed
179
                        logger.Debug(e,"TCPConn Receive_Poll 什么都收不到");
潘栩锋's avatar
潘栩锋 committed
180
                        return -1;
潘栩锋's avatar
潘栩锋 committed
181
                    }
潘栩锋's avatar
潘栩锋 committed
182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197
                    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)
潘栩锋's avatar
潘栩锋 committed
198
                    {
潘栩锋's avatar
潘栩锋 committed
199
                        logger.Debug(e, "TCPConn Receive_Poll 什么都收不到");
潘栩锋's avatar
潘栩锋 committed
200
                        return -1;
潘栩锋's avatar
潘栩锋 committed
201
                    }
潘栩锋's avatar
潘栩锋 committed
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237
                    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)
                {
潘栩锋's avatar
潘栩锋 committed
238
                    logger.Error("TCPConn OnPoll 长时间没收到任何数据 断开连接");
潘栩锋's avatar
潘栩锋 committed
239

潘栩锋's avatar
潘栩锋 committed
240 241 242 243 244 245 246 247
                    ret = -2;
                    goto end;
                }
            }
            else
            {
                while (true)
                {
潘栩锋's avatar
潘栩锋 committed
248
                    int packet_len = GetRecvInfoPacket();
潘栩锋's avatar
潘栩锋 committed
249 250
                    if (packet_len > 0)
                    {
潘栩锋's avatar
潘栩锋 committed
251
                        Parse_Packet(packet_len);
潘栩锋's avatar
潘栩锋 committed
252 253 254 255 256 257 258
                    }
                    else if (packet_len == 0)
                    {
                        break;
                    }
                    else 
                    {
潘栩锋's avatar
潘栩锋 committed
259
                        //异常
潘栩锋's avatar
潘栩锋 committed
260 261 262 263 264 265 266 267 268 269 270 271 272 273
                        ret = -1;
                        goto end;
                    }
                }
            }
            int sendlen = Send_Poll2();

            if (sendlen < 0)
            {
                ret = -1;
                goto end;
            }
        end:
            if (ret != 0)
潘栩锋's avatar
潘栩锋 committed
274 275
            {
                //连接断开,清空接收缓存区
潘栩锋's avatar
潘栩锋 committed
276
                logger.Error("TCPConn OnPoll 连接断开,清空接收缓存区");
潘栩锋's avatar
潘栩锋 committed
277 278

                in_buffer.Clear();
279 280 281 282
                lock(out_buffer)
                {
                    out_buffer.Clear();
                }
潘栩锋's avatar
潘栩锋 committed
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346
                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
    }
}