• BaseSocket


    namespace Shine
    {
        /** socket基类 */
        export class BaseSocket
        {
            /** 关闭的 */
            public static readonly Closed:number=1;
            /** 连接中 */
            public static readonly Connecting:number=2;
            /** 已连接 */
            public static readonly Connected:number=3;
    
            private static _connectTimeMax:number=5;
    
            /** 当前状态(主线程写,IO线程读) */
            private _state:number=1;
            /** 执行索引 */        
            private _doIndex:number=0;
    
        
            private _host:string;
            private _port:number;
            
            /** 是否析构了 */
            private _disposed:boolean=false;
            /** 连接计时 */
            private _connectTime:number=0;
    
            private _secondLastTime:number=0;
        
            /** 连接内容 */
            private _content:BaseSocketContent;
    
            //reconnect
            /** 是否允许断线重连 */
            private _openReconnect:boolean = false;
            /** 断线重连是否有效(是否达到缓存数目上限) */
            private _reconnecting:boolean = false;
            /** 重连剩余时间(秒) */
            private _reconnectLastTime:number=0;
    
            /** 间隔(3秒) */
            private _reConnectTime:AffairTimeOut;
    
            private _closeByInitiative:boolean;
        
            /** 接收连接ID */
            private _receiveID:number=-1;
            /** 接收令牌 */
            private _receiveToken:number=-1;
    
            /** 读流 */
            private _readStream:BytesReadStream = new BytesReadStream();
            /** 写流 */
            private _writeStream:BytesWriteStream = new BytesWriteStream();
    
            //ping
            /** 心跳计时(秒) */
            private _pingKeepTime:number;
            /** 心跳时间经过(秒) */
            private _pingTimePass:number = 0;
            /** ping间隔秒数 */
            private _pingIndex:number = 0;
        
            //try
            /** 当前尝试次数(-1就是未工作) */
            private _currentTryCount:number;
            /** 最多尝试次数 */
            private _tryCountMax:number = 0;
        
            /** 连接成功回调*/
            private _connectCall:Func;
            /** 连接失败回调*/
            private _connectFailedCall:Func;
            /** 连接被关闭回调*/
            private _closeCall:Func;
            /** 构造协议回调*/
            private _createResponseFunc:Func;
        
            //check
            /** 发送序号 */
            private _sendMsgIndex:number = 0;
            /** 接收协议序号 */
            private _receiveMsgIndex:number = 0;
    
            /** 发送消息缓存队列 */
            private _sendCacheRequestQueue:BaseRequest[];
            /** 断线时发送的序号 */
            private _disConnectLastSendIndex:number=0;
    
            constructor()
            {
                this._pingKeepTime = ShineSetting.pingKeepTime;
    
                this._sendCacheRequestQueue=new Array<BaseRequest>(ShineSetting.requestCacheLen);
    
                this._reConnectTime=new AffairTimeOut(Func.create(this,this.reconnectTimeOut),3);
            }
        
            /** 连接回调*/
            public setConnectCall(func: Func): void  
            {
                this._connectCall = func;
            }
        
            /* 连接失败回调 */
            public setConnectFailedCall(func: Func): void  
            {
                this._connectFailedCall = func;
            }
        
            /** 连接被关闭回调 */
            public setCloseCall(func: Func): void  
            {
                this._closeCall = func;
            }
        
            /** 构造协议回调 */
            public setCreateResponseFunc(func:Func): void  
            {
                this._createResponseFunc = func;
            }
        
            /** 清空(回归) */
            public clear(): void 
            {
                this._writeStream.clear();
                //序号归零
                this._sendMsgIndex = 0;
                this._receiveMsgIndex=0;
                this._reconnecting=false;
                this._reconnectLastTime=0;
                this._pingTimePass=0;
    
                this._receiveID=-1;
                this._receiveToken=-1;
            }
        
            /** 每帧 */
            public onFrame(delay: number): void  
            {
                this._secondLastTime += delay;
        
                if (this._secondLastTime >= 1000) 
                {
                    this._secondLastTime -= 1000;
        
                    this.onSecond();
                }
    
                this.sendLoopOnce();
            }
        
            /** 是否开启断线重连 */
            public setOpenReconnect(value: boolean): void 
            {
                this._openReconnect = value;
            }
        
            public isOpenReconnect(): boolean  
            {
                return this._openReconnect;
            }
        
            /** 是否连接着 */
            public isConnect(): boolean 
            {
                return this._state==BaseSocket.Connected;
            }
    
            /** 是否连接着 */
            public isConnecting(): boolean 
            {
                return this._state==BaseSocket.Connecting;
            }
    
            public getDoIndex():number
            {
                return this._doIndex;
            }
    
            /** 获取状态 */
            public getState():number
            {
                return this._state;
            }
    
            /** 设置接收连接信息 */
            public setReceiveInfo(receiveID:number,token:number):void
            {
                //已有
                if(this._receiveID>0)
                    return;
    
                this._receiveID=receiveID;
                this._receiveToken=token;
            }
        
            /** 连接 */
            public connect(host:string,port:number): void 
            {
                //连接尝试2次
                this._tryCountMax=2;
                this.preConnect(host,port);
            }
        
            /** 尝试连接(time:秒) */
            public tryConnect(host:string,port:number):void
            {
                //连接尝试3次
                this._tryCountMax=0;
                this.preConnect(host,port);
            }
        
            /** 重新尝试连接 */
            public reConnect():void
            {
                this.connect(this._host, this._port);
            }
    
            private retryConnect():void
            {
                this.toCloseForConnect();
                this.toConnectOnce();
            }
    
            public preConnectSuccessForIO():void
            {
                if(!this.isConnecting())
                    return;
    
                this._state=BaseSocket.Connected;
    
                //重连中
                if(this._reconnecting && this._receiveID>0)
                {
                    this.refreshPingTime();
                    this.sendAbs(SocketReconnectRequest.createSocketReconnect(this._receiveID,this._receiveToken,this._receiveMsgIndex));
                    this._reConnectTime.start();
                }
                else
                {
                    this.clear();
                    this.onConnectSuccess();
                }
            }
    
            private onConnectSuccess():void
            {
                if(this._connectCall!=null)
                    this._connectCall.invoke();
            }
    
            private preConnect(host:string,port:number): void  
            {
                this.close();
    
                this._host = host;
                this._port = port;
        
                this._currentTryCount = 0;
        
                this.toConnectOnce();
            }
    
            public closeForIO(isInitiative:boolean,canRec:boolean=true):void
            {
                if(this._state==BaseSocket.Closed)
                    return;
    
                //正在连接中
                if(this.isConnecting())
                {
                    this.stopConnect();
                }
    
                this._state=BaseSocket.Closed;
                this._doIndex++;//序号加
        
                Ctrl.print("连接断开",isInitiative);
    
                 if (isInitiative)
                {
                    this.toFlush();
                }
    
                this.onDisconnect();
    
                //重连中,直接判定失败
                if(!this._reconnecting && this._openReconnect && !isInitiative && canRec && this.canReconnect())
                {
                    Ctrl.log("连接断线,进入重连阶段");
                    this._reconnecting=true;
                    this._disConnectLastSendIndex=this._sendMsgIndex;
                    this._reconnectLastTime=ShineSetting.socketReConnectKeepTime;
                    this._closeByInitiative=isInitiative;
    
                    this.beginReconnect();
                }
                else
                {
                    this._closeByInitiative=isInitiative;
                    this.realClose();
                }
            }
    
            /** 开始重连(io线程) */
            protected beginReconnect():void
            {
                this._tryCountMax=0;
                this.reConnect();
            }
    
            /** 实际关闭(IO线程) */
            protected realClose():void
            {
                this._receiveID=-1;
                this._receiveToken=-1;
                this._reConnectTime.stop();
    
                this._reconnecting=false;
                this._disConnectLastSendIndex=0;
    
                for(var i:number=this._sendCacheRequestQueue.length-1;i>=0;--i)
                {
                    this._sendCacheRequestQueue[i]=null;
                }
    
                if(!this._closeByInitiative)
                {
                    if(this._closeCall!=null)
                        this._closeCall.invoke();
                }
            }
    
            /** 是否可重连 */
            protected canReconnect():boolean
            {
                return this._receiveID>0;
            }
    
            /** try到时间(io线程) */
            private reconnectTimeOut():void
            {
                this.reconnectFailed();
            }
    
            /** 重连失败(IO线程) */
            protected reconnectFailed():void
            {
                if(!this._reconnecting)
                    return;
    
                if(this.isConnecting())
                {
                    this.stopConnect();
                }
    
                this.realClose();
            }
    
            /** 停止连接 */
            protected stopConnect():void
            {
    
            }
    
            private onDisconnect():void
            {
                if(this._content!=null)
                {
                    this._content.close();
                    this._content=null;
                }
    
                this._reConnectTime.stop();
            }
    
            private toCloseForConnect():void
            {
                if(this._state==BaseSocket.Closed)
                    return;
    
                this._state=BaseSocket.Closed;
    
                this._doIndex++;//序号加
    
                this.onDisconnect();
            }
        
            /** 推送剩余的消息 */
            private toFlush():void
            {
                this.sendLoopOnce();
            }
        
            private doConnectFailed():void
            {
                if(this._connectFailedCall!=null)
                    this._connectFailedCall.invoke();
            }
        
            //被关闭
            public beClose():void
            {
                this.closeForIO(false);
            }
        
            /** 关闭(不调closeCall) */
            public close():void
            {
                this.closeForIO(true);
            }
    
            /** 闪断测试 */
            public closeTest():void
            {
                this.closeForIO(false);
            }
        
            /** 刷ping的时间 */
            public refreshPingTime():void
            {
                this._pingTimePass = 0;
            }
    
            /** 真析构 */
            public dispose():void
            {
                this.closeAndClear();
                //TODO:后续
            }
        
            /** 析构 */
            public closeAndClear():void
            {
                this.close();
                this.clear();
            }
        
            private onSecond():void
            {
                switch(this._state)
                {
                    case BaseSocket.Connected:
                    {
                        // if(!_socket.Connected)
                        // {
                        //     //连接被关闭
                        //     beClose();
                        // }
    
                        ++this._pingIndex;
    
                        if(this._pingIndex>=ShineSetting.pingTime)
                        {
                            this._pingIndex=0;
    
                            this.sendPingRequet();
                        }
    
                        if(ShineSetting.needPingCut)
                        {
                            ++this._pingTimePass;
    
                            if(this._pingTimePass>ShineSetting.pingKeepTime)
                            {
                                Ctrl.warnLog("连接超时,强制关闭");
    
                                this.closeForIO(false);
                            }
                        }
                    }
                        break;
                    case BaseSocket.Connecting:
                    {
                        //连接超时
                        if((++this._connectTime)>=5)
                        {
                            this.connectTimeOut();
                        }
                    }
                        break;
                }
            }
        
            private toConnectOnce():void 
            {
                this.createNewContent();
    
                this._state=BaseSocket.Connecting;
                this._connectTime=0;
                ++this._currentTryCount;
    
                Ctrl.print("toConnect一次:",this._host);
    
                this._content.connect(this._host, this._port);
            }
    
            private createNewContent():void
            {
                ++this._doIndex;
                this._content=new BaseSocketContent(this);
                this._content.setDoIndex(this._doIndex);
            }
    
            public preConnectFailedForIO():void
            {
                if(!this.isConnecting())
                    return;
    
                this.toCloseForConnect();
    
                //超出次数限制
                if(this._tryCountMax>0 && this._currentTryCount>=this._tryCountMax)
                {
                    this._currentTryCount=-1;
                    this._connectTime=0;
    
                    if(this._connectFailedCall!=null)
                        this._connectFailedCall.invoke();
                }
                else
                {
                    this.retryConnect();
                }
            }
    
            private connectTimeOut():void
            {
                if(this._state!=BaseSocket.Connecting)
                    return;
    
                close();
    
                //超出次数限制
                if(this._tryCountMax>0 && this._currentTryCount>=this._tryCountMax)
                {
                    this._currentTryCount=-1;
                    this._connectTime=0;
                    this.doConnectFailed();
                }
                else
                {
                    this.retryConnect();
                }
            }
        
            private sendLoopOnce():void
            {
                if(!this.isConnect())
                    return;
    
                //当前没有
                if(this._content==null)
                    return;
    
                if (this._writeStream.length() > 0)
                {
                    this._content.sendOnce(this._writeStream.getByteArray());
                    this._writeStream.clear();
                }
            }
        
            private toSendOne(request:BaseRequest):void
            {
                this.toWriteRequestToStream(this._writeStream,request,request.sendMsgIndex);
            }
        
            /** 实际执行写request到stream */
            private toWriteRequestToStream(stream:BytesWriteStream,request:BaseRequest,index:number):void
            {
                var limit:number=request.getMessageLimit();
                stream.setWriteLenLimit(limit);
    
                var startPos:number=stream.getPosition();
    
                var mid:number=request.getDataID();
    
                //写协议ID(原生写)
                stream.natureWriteUnsignedShort(mid);
    
                if(!BytesControl.isIgnoreMessage(mid))
                {
                    stream.natureWriteShort(index);
                }
    
                request.writeToStream(stream);
    
                var endPos:number=stream.getPosition();
                var len:number=endPos-startPos;
    
                if(len>=limit)
                {
                    Ctrl.errorLog("request长度超出上限",len);
                }
    
                if(ShineSetting.needCustomLengthBasedFrameDecoder)
                {
                    stream.insertLenToPos(startPos,len);
                }
                else
                {
                    stream.setPosition(startPos);
    
                    stream.insertVoidBytes(4,len);
    
                    stream.natureWriteInt(len);
    
                    stream.setPosition(endPos);
                }
            }
    
            /** 重连的下一步(主线程) */
            protected doReconnectNext(lastReceiveIndex:number,needReMsg:boolean):void
            {
                //清空
                this._writeStream.clear();
    
                var dd:number=this.indexD(this._sendMsgIndex,lastReceiveIndex);
    
                if(dd<0 || dd>=ShineSetting.requestCacheLen)
                {
                    Ctrl.warnLog("重连时,消息缓存已失效");
    
                    this.closeForIO(false,false);
                    return;
                }
    
                if(needReMsg)
                {
                    this.sendAbs(SocketReconnectSuccessRequest.createSocketReconnectSuccess(this._receiveMsgIndex));
                }
    
                for(var i=lastReceiveIndex;this.indexD(i,this._sendMsgIndex)<0;i++)
                {
                    var request:BaseRequest=this._sendCacheRequestQueue[i & ShineSetting.requestCacheMark];
    
                    if(request==null)
                    {
                        Ctrl.errorLog("不该找不到消息");
                        this.closeForIO(false,false);
                        return;
                    }
                    else
                    {
                        this.doWriteRequestToStream(request,i);
                    }
                }
    
                this._reconnecting=false;
                this._disConnectLastSendIndex=0;
    
                //推送一次
                this.toFlush();
    
                Ctrl.log("socket重连成功:");
            }
    
            /** 读取一个 */
            public onePiece(bytes: ArrayBuffer): void 
            {
                //更新ping时间
                this.refreshPingTime();
                this.onSocketDataT(bytes);
            }
    
            /** 收到一个协议包(IO线程) */
            private onSocketDataT(bytes: ArrayBuffer): void 
            {
                this._readStream.setBuf(bytes);
        
                var mid: number = this._readStream.natureReadUnsignedShort();
        
                //检测序号
                if(!BytesControl.isIgnoreMessage(mid))
                {
                    var receiveIndex:number=this._readStream.natureReadShort();
    
                    var nowIndex:number=this._receiveMsgIndex;
    
                    if(receiveIndex!=nowIndex)
                    {
                        Ctrl.warnLog("序号检测没对上,"+" nowIndex:"+nowIndex+" receiveIndex:"+receiveIndex+" mid:"+mid);
    
                        //视为被动关闭
                        this.closeForIO(false);
    
                        return;
                    }
    
                    ++this._receiveMsgIndex;
                }
        
                if (this._createResponseFunc != null) 
                {
                    var response:BaseResponse = this._createResponseFunc.invoke(mid);
        
                    if (response == null) 
                    {
                        if (ShineSetting.needMessageExistCheck)
                        {
                            Ctrl.throwError("未解析mid为" + mid + "的协议");
                        }
        
                        return;
                    }
        
                    response.socket = this;
        
                    if ((response = response.readFromStream(this._readStream)) != null) 
                    {
                        this.toRunResponseOne(response);
                    }
                }
            }
        
            /** 读失败 */
            private onError(msg: string): void
             {
                 Ctrl.print("socket读取失败:" + msg);
        
                //断开连接
                close();
            }
        
            //心跳回复(io线程)
            private onRePing(): void
            {
                this.refreshPingTime();
            }
        
            //执行消息
            private makeResponse(mid:number): void 
            {
        
            }
        
            /** 执行response们 */
            private toRunResponseOne(response:BaseResponse):void
            {
                if (ShineSetting.needShowMessage && !BytesControl.isIgnoreMessage(response.getDataID()))
                {
                  Ctrl.debugLog("收消息:","mid:"+response.getDataID(),ShineSetting.needShowMessageDetail ? response.toDataString() : response.getDataClassName());
                }
        
                if (ShineSetting.needError)
                {
                    response.run();
                }
                else
                {
                    try 
                    {
                        response.run();
                    }
                    catch (err)
                    {
                        Ctrl.throwError(err);
                    }
                }
            }
        
            /** 发送ping消息 */
            private sendPingRequet(): void 
            {
                this.sendAbs(PingRequest.createPing());
            }
        
            //check
        
            /** 发送到连接 */
            public send(request:BaseRequest): void 
            {
                if (ShineSetting.needShowMessage) 
                {
                    var mid:number = request.dataID;
        
                    Ctrl.debugLog("发消息:","mid:"+mid,ShineSetting.needShowMessageDetail ? request.toDataString() : request.getDataClassName());
                }
        
                //重连中
                if(this.checkRequestNeedSend(request))
                {
                    request.preSend();
    
                    this.sendRequestForIO(request);
                }
            }
    
            /** 发送request(IO线程) */
            protected sendRequestForIO(request:BaseRequest):void
            {
                if(!this.checkRequestNeedSend(request))
                    return;
    
                var needIndex:boolean=false;
                var index:number=0;
    
                if(!BytesControl.isIgnoreMessage(request.getDataID()))
                {
                    needIndex=true;
                    index=this._sendMsgIndex++;
    
                    if(this._sendMsgIndex>32767)
                        this._sendMsgIndex-=65536;
    
                    //存起
                    this._sendCacheRequestQueue[index & ShineSetting.requestCacheMark]=request;
                }
    
                if(this._reconnecting)
                {
                    if(needIndex)
                    {
                        //失效
                        if(this.indexD(index,this._disConnectLastSendIndex)>=ShineSetting.requestCacheLen)
                        {
                            this.reconnectFailed();
                        }
                    }
                }
                else
                {
                    this.doWriteRequestToStream(request,index);
                }
            }
    
            /** 发abs消息 */
            public sendAbs(request:BaseRequest):void
            {
                request.preSend();
    
                if(this.isConnect())
                {
                    this.doWriteRequestToStream(request,0);
                }
            }
    
            private checkRequestNeedSend(request:BaseRequest):boolean
            {
                //重连中
                if(this._reconnecting)
                {
                    //不保留的
                    if(!request.needCacheOnDisConnect())
                        return false;
                }
                else
                {
                    //还未连接
                    if(!this.isConnect())
                        return false;
                }
    
                return true;
            }
            
            /** 执行写入流(io线程) */
            private doWriteRequestToStream(request:BaseRequest,index:number):void
            {
                this.toWriteRequestToStream(this._writeStream,request,index);
            }
    
            /** 返回a1-a2 */
            public indexD(a1:number,a2:number):number
            {
                var re:number=a1 - a2;
    
                if(re>32767)
                    re-=65536;
    
                if(re<-32768)
                    re+=65536;
    
                return re;
            }
    
            /** 收到重连成功(IO消息) */
            public onReconnectSuccess(lastReceiveIndex:number):void
            {
                //已不在重连中
                if(!this._reconnecting)
                {
                    this.closeForIO(false,false);
                    return;
                }
    
                this.doReconnectNext(lastReceiveIndex,false);
            }
        }
    }
  • 相关阅读:
    Leetcode 349. Intersection of Two Arrays
    hdu 1016 Prime Ring Problem
    map 树木品种
    油田合并
    函数学习
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 102. Binary Tree Level Order Traversal
    Leetcode 101. Symmetric Tree
    poj 2524 Ubiquitous Religions(宗教信仰)
    pat 1009. 说反话 (20)
  • 原文地址:https://www.cnblogs.com/porter/p/13370862.html
Copyright © 2020-2023  润新知