nps/lib/mux/conn.go

174 lines
3.7 KiB
Go
Raw Normal View History

2019-02-26 14:40:28 +00:00
package mux
import (
"errors"
2019-08-23 10:53:36 +00:00
"github.com/cnlh/nps/lib/common"
2019-02-26 14:40:28 +00:00
"github.com/cnlh/nps/lib/pool"
2019-08-23 10:53:36 +00:00
"github.com/cnlh/nps/vender/github.com/astaxie/beego/logs"
2019-02-26 14:40:28 +00:00
"io"
"net"
"time"
)
type conn struct {
net.Conn
getStatusCh chan struct{}
connStatusOkCh chan struct{}
connStatusFailCh chan struct{}
readTimeOut time.Time
writeTimeOut time.Time
readBuffer []byte
startRead int //now read position
endRead int //now end read
readFlag bool
readCh chan struct{}
2019-03-15 06:03:49 +00:00
waitQueue *sliceEntry
stopWrite bool
2019-02-26 14:40:28 +00:00
connId int32
isClose bool
readWait bool
2019-03-18 06:18:58 +00:00
hasWrite int
2019-02-26 14:40:28 +00:00
mux *Mux
}
2019-03-15 06:03:49 +00:00
func NewConn(connId int32, mux *Mux) *conn {
c := &conn{
readCh: make(chan struct{}),
2019-02-26 14:40:28 +00:00
getStatusCh: make(chan struct{}),
connStatusOkCh: make(chan struct{}),
connStatusFailCh: make(chan struct{}),
2019-03-15 06:03:49 +00:00
waitQueue: NewQueue(),
2019-02-26 14:40:28 +00:00
connId: connId,
mux: mux,
}
2019-03-15 06:03:49 +00:00
return c
2019-02-26 14:40:28 +00:00
}
func (s *conn) Read(buf []byte) (n int, err error) {
2019-03-15 06:03:49 +00:00
if s.isClose || buf == nil {
2019-02-26 14:40:28 +00:00
return 0, errors.New("the conn has closed")
}
2019-03-15 06:03:49 +00:00
if s.endRead-s.startRead == 0 { //read finish or start
if s.waitQueue.Size() == 0 {
s.readWait = true
if t := s.readTimeOut.Sub(time.Now()); t > 0 {
timer := time.NewTimer(t)
defer timer.Stop()
select {
case <-timer.C:
s.readWait = false
return 0, errors.New("read timeout")
case <-s.readCh:
}
} else {
<-s.readCh
}
2019-03-15 06:03:49 +00:00
}
if s.isClose { //If the connection is closed instead of continuing command
return 0, errors.New("the conn has closed")
}
if node, err := s.waitQueue.Pop(); err != nil {
s.Close()
return 0, io.EOF
} else {
2019-03-15 06:03:49 +00:00
pool.PutBufPoolCopy(s.readBuffer)
2019-08-23 10:53:36 +00:00
if node.val == nil {
//close
s.Close()
logs.Warn("close from read msg ", s.connId)
} else {
s.readBuffer = node.val
s.endRead = node.l
s.startRead = 0
}
2019-02-26 14:40:28 +00:00
}
}
if len(buf) < s.endRead-s.startRead {
n = copy(buf, s.readBuffer[s.startRead:s.startRead+len(buf)])
s.startRead += n
} else {
n = copy(buf, s.readBuffer[s.startRead:s.endRead])
2019-03-15 06:03:49 +00:00
s.startRead += n
}
return
2019-02-26 14:40:28 +00:00
}
2019-08-23 10:53:36 +00:00
func (s *conn) Write(buf []byte) (n int, err error) {
2019-02-26 14:40:28 +00:00
if s.isClose {
return 0, errors.New("the conn has closed")
}
ch := make(chan struct{})
go s.write(buf, ch)
2019-02-26 14:40:28 +00:00
if t := s.writeTimeOut.Sub(time.Now()); t > 0 {
timer := time.NewTimer(t)
2019-03-15 06:03:49 +00:00
defer timer.Stop()
2019-02-26 14:40:28 +00:00
select {
case <-timer.C:
return 0, errors.New("write timeout")
case <-ch:
2019-02-26 14:40:28 +00:00
}
} else {
<-ch
2019-02-26 14:40:28 +00:00
}
if s.isClose {
return 0, io.EOF
}
return len(buf), nil
}
func (s *conn) write(buf []byte, ch chan struct{}) {
start := 0
l := len(buf)
for {
if l-start > pool.PoolSizeCopy {
2019-08-23 10:53:36 +00:00
s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:start+pool.PoolSizeCopy])
start += pool.PoolSizeCopy
} else {
2019-08-23 10:53:36 +00:00
s.mux.sendInfo(common.MUX_NEW_MSG, s.connId, buf[start:l])
break
}
}
ch <- struct{}{}
}
2019-02-26 14:40:28 +00:00
func (s *conn) Close() error {
2019-03-15 06:03:49 +00:00
if s.isClose {
2019-08-23 10:53:36 +00:00
logs.Warn("already closed", s.connId)
2019-02-26 14:40:28 +00:00
return errors.New("the conn has closed")
}
s.isClose = true
pool.PutBufPoolCopy(s.readBuffer)
2019-03-15 06:03:49 +00:00
if s.readWait {
s.readCh <- struct{}{}
}
s.waitQueue.Clear()
s.mux.connMap.Delete(s.connId)
2019-03-02 09:43:21 +00:00
if !s.mux.IsClose {
2019-08-23 10:53:36 +00:00
s.mux.sendInfo(common.MUX_CONN_CLOSE, s.connId, nil)
}
2019-02-26 14:40:28 +00:00
return nil
}
func (s *conn) LocalAddr() net.Addr {
return s.mux.conn.LocalAddr()
}
func (s *conn) RemoteAddr() net.Addr {
return s.mux.conn.RemoteAddr()
}
func (s *conn) SetDeadline(t time.Time) error {
s.readTimeOut = t
s.writeTimeOut = t
return nil
}
func (s *conn) SetReadDeadline(t time.Time) error {
s.readTimeOut = t
return nil
}
func (s *conn) SetWriteDeadline(t time.Time) error {
s.writeTimeOut = t
return nil
}