有深入研究的 golang websocket 的大佬吗?遇到一个 30 秒自动断开的问题?

查看 287|回复 30
作者:meshell   
目前问题是这样的如果发送的消息不是 OpText,OpBinary 这两种类型的话,连接会在 30 秒自动断开。
我定时不管是服务端还是客户端发送 opPing 也会断开。
只有一直定时发 OpText,OpBinary 这两种类型才不会断开。
看了源码也没有发现这个 30 秒在那里设置的。
库是: github.com/gobwas/ws
这是抓包到断的最后几条记录..

第 2 条附言  ·  2 小时 50 分钟前
       // 这是服务端的代码
        for {
                        // set SetReadDeadline
                        err := conn.SetReadDeadline(time.Time{})
                        if err != nil {
                                logger.Errorf("SetReadDeadline failed: %s", err)
                                // do something else, for example create new conn
                                return
                        }
                        messages, err := wsutil.ReadClientMessage(client.conn, []wsutil.Message{})
                        if err != nil { // Read error
                                logger.Infof("Websocket read error from client [%s] - %s", client.ID(), err)
                                return
                        }
                        for _, msg := range messages {
                                switch msg.OpCode {
                                case ws.OpText, ws.OpBinary:
                                        if wh.srv.OnData == nil {
                                                logger.Errorf("websocket handler on data handler not setting, body: %s", string(msg.Payload))
                                                return
                                        }
                                        if err = wh.srv.OnData(client, msg.Payload); err != nil {
                                                logger.Errorf("websocket handler data failure, body: %s err: %v", string(msg.Payload), err)
                                        }
                                case ws.OpClose: // Close
                                        logger.Infof("receive client closed")
                                case ws.OpPing: // Ping
                                        logger.Infof("receive client ping control message")
                                        if err := wsutil.WriteServerMessage(conn, ws.OpPong, nil); err != nil {
                                                logger.Errorf("send pong control message failure, err: %v", err)
                                        }
                                case ws.OpContinuation: // Continuation
                                        logger.Infof("receive client continuation")
                                case ws.OpPong: // Pong
                                        logger.Infof("receive pong....")
                                default: // WTF -_-!
                                        logger.Errorf("receive error message from client: %s, op: %v", string(msg.Payload), msg.OpCode)
                                }
                        }
                }
        }()
第 3 条附言  ·  2 小时 50 分钟前
```golang
// 这是客户端的代码。。。
go func() {
defer conn.Close()
for {
messages, err := wsutil.ReadServerMessage(conn, []wsutil.Message{})
if err != nil {
logger.Infof("read error: %+v", err)
return
}
logger.Infof("on receive message: %+v", messages)
for _, msg := range messages {
switch msg.OpCode {
case ws.OpText, ws.OpBinary:
if client.OnData != nil {
err := client.OnData(client, msg.Payload)
if err != nil {
logger.Infof("on receive data error: %s", err)
}
}
case ws.OpPing:
logger.Infof("on receive ping message")
_ = wsutil.WriteClientMessage(conn, ws.OpPong, nil)
case ws.OpPong:
logger.Infof("on receive pong message")
case ws.OpClose:
logger.Infof("on receive close message")
return
}
}
}
}()
go func() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
_ = conn.Close()
}()
for {
select {
case // 重新贴下客户端代码
        go func() {
                defer conn.Close()
                for {
                        messages, err := wsutil.ReadServerMessage(conn, []wsutil.Message{})
                        if err != nil {
                                logger.Infof("read error: %+v", err)
                                return
                        }
                        logger.Infof("on receive message: %+v", messages)
                        for _, msg := range messages {
                                switch msg.OpCode {
                                case ws.OpText, ws.OpBinary:
                                        if client.OnData != nil {
                                                err := client.OnData(client, msg.Payload)
                                                if err != nil {
                                                        logger.Infof("on receive data error: %s", err)
                                                }
                                        }
                                case ws.OpPing:
                                        logger.Infof("on receive ping message")
                                        _ = wsutil.WriteClientMessage(conn, ws.OpPong, nil)
                                case ws.OpPong:
                                        logger.Infof("on receive pong message")
                                case ws.OpClose:
                                        logger.Infof("on receive close message")
                                        return
                                }
                        }
                }
        }()
        go func() {
                ticker := time.NewTicker(pingPeriod)
                defer func() {
                        ticker.Stop()
                        _ = conn.Close()
                }()
                for {
                        select {
                        case
第 5 条附言  ·  45 分钟前
我靠。。。。找到原因了。。。代码里面有一个定时任务检测链接距离上次活动 30 秒没有更新就断开这个链接。。。。😂😂😂😂
hxzhouh1   
这是抓包到断的最后几条记录..

hxzhouh1   
       // 这是服务端的代码
        for {
                        // set SetReadDeadline
                        err := conn.SetReadDeadline(time.Time{})
                        if err != nil {
                                logger.Errorf("SetReadDeadline failed: %s", err)
                                // do something else, for example create new conn
                                return
                        }
                        messages, err := wsutil.ReadClientMessage(client.conn, []wsutil.Message{})
                        if err != nil { // Read error
                                logger.Infof("Websocket read error from client [%s] - %s", client.ID(), err)
                                return
                        }
                        for _, msg := range messages {
                                switch msg.OpCode {
                                case ws.OpText, ws.OpBinary:
                                        if wh.srv.OnData == nil {
                                                logger.Errorf("websocket handler on data handler not setting, body: %s", string(msg.Payload))
                                                return
                                        }
                                        if err = wh.srv.OnData(client, msg.Payload); err != nil {
                                                logger.Errorf("websocket handler data failure, body: %s err: %v", string(msg.Payload), err)
                                        }
                                case ws.OpClose: // Close
                                        logger.Infof("receive client closed")
                                case ws.OpPing: // Ping
                                        logger.Infof("receive client ping control message")
                                        if err := wsutil.WriteServerMessage(conn, ws.OpPong, nil); err != nil {
                                                logger.Errorf("send pong control message failure, err: %v", err)
                                        }
                                case ws.OpContinuation: // Continuation
                                        logger.Infof("receive client continuation")
                                case ws.OpPong: // Pong
                                        logger.Infof("receive pong....")
                                default: // WTF -_-!
                                        logger.Errorf("receive error message from client: %s, op: %v", string(msg.Payload), msg.OpCode)
                                }
                        }
                }
        }()
Oneman   
```golang
// 这是客户端的代码。。。
go func() {
defer conn.Close()
for {
messages, err := wsutil.ReadServerMessage(conn, []wsutil.Message{})
if err != nil {
logger.Infof("read error: %+v", err)
return
}
logger.Infof("on receive message: %+v", messages)
for _, msg := range messages {
switch msg.OpCode {
case ws.OpText, ws.OpBinary:
if client.OnData != nil {
err := client.OnData(client, msg.Payload)
if err != nil {
logger.Infof("on receive data error: %s", err)
}
}
case ws.OpPing:
logger.Infof("on receive ping message")
_ = wsutil.WriteClientMessage(conn, ws.OpPong, nil)
case ws.OpPong:
logger.Infof("on receive pong message")
case ws.OpClose:
logger.Infof("on receive close message")
return
}
}
}
}()
go func() {
ticker := time.NewTicker(pingPeriod)
defer func() {
ticker.Stop()
_ = conn.Close()
}()
for {
select {
case // 重新贴下客户端代码
        go func() {
                defer conn.Close()
                for {
                        messages, err := wsutil.ReadServerMessage(conn, []wsutil.Message{})
                        if err != nil {
                                logger.Infof("read error: %+v", err)
                                return
                        }
                        logger.Infof("on receive message: %+v", messages)
                        for _, msg := range messages {
                                switch msg.OpCode {
                                case ws.OpText, ws.OpBinary:
                                        if client.OnData != nil {
                                                err := client.OnData(client, msg.Payload)
                                                if err != nil {
                                                        logger.Infof("on receive data error: %s", err)
                                                }
                                        }
                                case ws.OpPing:
                                        logger.Infof("on receive ping message")
                                        _ = wsutil.WriteClientMessage(conn, ws.OpPong, nil)
                                case ws.OpPong:
                                        logger.Infof("on receive pong message")
                                case ws.OpClose:
                                        logger.Infof("on receive close message")
                                        return
                                }
                        }
                }
        }()
        go func() {
                ticker := time.NewTicker(pingPeriod)
                defer func() {
                        ticker.Stop()
                        _ = conn.Close()
                }()
                for {
                        select {
                        case
meshell
OP
  
我靠。。。。找到原因了。。。代码里面有一个定时任务检测链接距离上次活动 30 秒没有更新就断开这个链接。。。。😂😂😂😂
meshell
OP
  
有没有可能是防火墙干的? 抓包看看?
david98   
有没有可能是防火墙干的? 抓包看看?
@hxzhouh1 我遇到过某个环境,网关/防火墙 会 90s 定时把 stream 断掉
kuanat   
排除法,防火墙检查,换另外服务端测试,换另外客户端测试。
目测可能是服务端代码,有 30 秒的检查
meshell
OP
  
@hxzhouh1 我是 mac 应该没有这么一说吧。我把本地的代理关了也是一样的。
Ipsum   
@OneMan 目前两端都是 go 程序测试的,我试试浏览器不发 text,bin 测试下。
您需要登录后才可以回帖 登录 | 立即注册

返回顶部