设计思路:每个websocket允许的连接都是有时间限制的,超时后服务端会自动断开连接,那么长连接就在服务端发出断开连接信息后客户端检测断开信息再次发起连接请求,中间再通过握手信息确保客户端同服务器处于连接状态。
设计结构:
type Longsocket struct {
Ws *websocket.Conn
writeCh chan []byte
readCh chan []byte
ShakeHand bool
Url string
Protocol string
Origin string
BufferSize int
Status int
mu sync.Mutex
}
长连接通过`writeCh`通道主动向连接方发送消息,通过`ReadCh`通道读取连接中的信息,设置`ShakeHand`来确定是否要发送握手信息,Status用以标识连接状态。
通过WriteLoop来发送握手信息,同时监听`WriteCh`通道,转发通道里的消息。
//call func with a gorouting, it will send shake hands message to service to make sure self is ok
//if you want to send message call func 'Write', and the case writeCh will be vaild
func (l *Longsocket) WriteLoop() {
defer func() {
if err := recover(); err != nil {
//fmt.Println("writeloop", err)
}
}()
for {
errCount := 0
if l.Status != STATUS_CONNECT {
break
}
select {
case <-time.After(time.Second * time.Duration(SHAKE_HANDS_FREQUENCY)):
if l.ShakeHand {
_, err := l.Ws.Write([]byte(SHAKE_HANDS_MSG))
if err != nil {
errCount++
}
}
case msg := <-l.writeCh:
_, err := l.Ws.Write(msg)
if err != nil {
errCount++
}
}
if errCount != 0 {
break
}
}
l.Close()
}
通过ReadLoop来接受信息,同时将消息转发到`ReadCh`通道内。
//read message form socket and write them to readCh
func (l *Longsocket) ReadLoop() {
defer func() {
if err := recover(); err != nil {
//fmt.Println("readloop", err)
}
}()
for {
if l.Status != STATUS_CONNECT {
break
}
buf := make([]byte, l.BufferSize)
n, err := l.Ws.Read(buf)
if err != nil {
break
}
if n > 0 {
l.readCh <- buf[0:n]
}
}
l.Close()
}
然后可以通过Read函数将消息转发到形如
type dealmsg func([]byte, *Longsocket) error
的函数中去做相应的消息处理,当然你也可以通过Longsocket参数发送相应的处理消息。
源码已上传githup如下,其中有demo供参考。
https://github.com/qianlnk/longsocket