// package connstat NOTICE 待整理,未正式使用 package connstat import ( "sync/atomic" "time" ) // 高性能场景下实现长连接流数据读写超时功能 // 不使用Go的库函数SetDeadline // 也不在每次读写数据时使用time now获取读写时间 // 允许出现两秒左右的误差 type ConnStat struct { readTimeout int64 writeTimeout int64 totalReadByte uint64 totalWriteByte uint64 prevTotalReadByte uint64 prevTotalWriteByte uint64 lastReadActiveTick int64 lastWriteActiveTick int64 } // 单位秒,设置为0则用于不超时 func (cs *ConnStat) Start(readTimeout int64, writeTimeout int64) { cs.readTimeout = readTimeout cs.writeTimeout = writeTimeout now := time.Now().Unix() cs.lastReadActiveTick = now cs.lastWriteActiveTick = now } func (cs *ConnStat) Read(n int) { atomic.AddUint64(&cs.totalReadByte, uint64(n)) } func (cs *ConnStat) Write(n int) { atomic.AddUint64(&cs.totalWriteByte, uint64(n)) } // 检查时传入当前时间戳。检查频率应该小于超时阈值。频率越低,则越精确 func (cs *ConnStat) Check(now int64) (isReadTimeout bool, isWriteTimeout bool) { if cs.readTimeout == 0 { // 没有设置,则不用检查 isReadTimeout = false } else { trb := atomic.LoadUint64(&cs.totalReadByte) if trb == 0 { // 历史从来没有收到过数据 isReadTimeout = (now - cs.lastReadActiveTick) > cs.readTimeout } else { if trb-cs.prevTotalReadByte > 0 { // 距离上次检查有收到过数据 isReadTimeout = false cs.lastReadActiveTick = now } else { isReadTimeout = (now - cs.lastReadActiveTick) > cs.readTimeout } } cs.prevTotalReadByte = trb } if cs.writeTimeout == 0 { isWriteTimeout = false } else { twb := atomic.LoadUint64(&cs.totalWriteByte) if twb == 0 { isWriteTimeout = (now - cs.lastWriteActiveTick) > cs.writeTimeout } else { if twb-cs.prevTotalWriteByte > 0 { isWriteTimeout = false cs.lastWriteActiveTick = now } else { isWriteTimeout = (now - cs.lastWriteActiveTick) > cs.writeTimeout } } cs.prevTotalWriteByte = twb } return }