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

228 天前
 meshell

目前问题是这样的如果发送的消息不是 OpText,OpBinary 这两种类型的话,连接会在 30 秒自动断开。

我定时不管是服务端还是客户端发送 opPing 也会断开。

只有一直定时发 OpText,OpBinary 这两种类型才不会断开。

看了源码也没有发现这个 30 秒在那里设置的。

库是: github.com/gobwas/ws

2276 次点击
所在节点    程序员
31 条回复
meshell
227 天前
@cgtx 哈哈
meshell
227 天前
@mango88 你是什么环境下测试的。。
kuanat
227 天前
@meshell #17

你给的截图里,最后一次客户端 ACK 确认服务端 Pong 之后,服务端主动发送 FIN ,说明断开是服务端的行为。

这个断开没有 opClose ,说明不是你的程序、也不是 ws 库的行为。

因为你是本地测试,也不会涉及防火墙。

由于 Ping/Pong 的间隔是 2s ,有双向通信,说明不是 Idle 相关的超时。也就是说,并不是 KeepAlive 等机制触发的先断开底层,再断开上层。

整个协议层面,在 ws 之下,还有(大概率)标准库 net/http ,再下层就是系统的 tcp socket 了。

我记忆中标准库 DefaultTransport 有个 30s 超时,查了一下 https://go.dev/src/net/http/transport.go 确实有,但是应该与你的问题无关。

正好你说你用的不是 http.client ,可以贴一下最小可复现的完整代码。因为之前的代码看不到 conn 的来源,可能是有哪个地方设置了超时参数。
meshell
227 天前
@kuanat

```golang
func (wh *wsHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
conn, _, _, err := ws.UpgradeHTTP(r, w)
if err != nil {
logger.Errorf("Websocket upgrade failed : %s", err)

return
}

client := &Client{
conn: conn,
// fd: nfd(conn),
server: wh.srv,
id: uuid.New(),
}

logger.Infof("Client [%s] connected to [%s] as [%s]", conn.RemoteAddr(), conn.LocalAddr(), client.id)
wh.srv.Lock()
wh.srv.clients[client.id] = client
wh.srv.Unlock()
if wh.srv.OnConnect != nil {
wh.srv.OnConnect(client)
}
// ... 下面的代码就是上面发的。这里的代码就是调用 ws 库,升级成 websocket.. 拿到链接.
}
```
jioswu
227 天前
我好像也遇到过这个问题,蹲一个解答 哈哈哈
kuanat
227 天前
@meshell #24

继续往下查吧,wh.srv 可能做了些什么操作。随便猜一下,可能是某个 context 有 30s 的设置,超时之后直接在 http 层面触发了 defer Close() 之类的操作,这个操作完成了 tcp 层面 FIN/ACK 的关闭,结果导致 ws 层面是没有 opClose 消息的。

我看了一下 gobwas/ws 的代码,UpgradeHTTP 这里就把 net.Conn 的 deadline 给清除了(设置了 time.Time 的零值)。(既然是无超时,理论上每次读 message 的时候 err := conn.SetReadDeadline(time.Time{}) 这个重置就没有必要了,不过与你的问题无关)
tywtyw2002
227 天前
你先测试下 15s pingpong 会不会断,如果不断 大概率就是他们说的 30s http 层的问题。

如果 15s 也断,那就一层层看代码往上找吧,最后走到 socket 层。
meshell
227 天前
@kuanat 大佬结案了 。。。。特默代码其它地方的问题。。。其它地方有定时器。。一开始没有没有仔细去看完整代码。。。只管实现了 。。。
meshell
227 天前
@tywtyw2002 结案了。😭
lasuar
227 天前
在它的代码库搜 ‘30’ 或者 Second 挨个看。
lasuar
227 天前
现在很多 web 框架也内置了 ws ,比如 gin iris ,或者可以使用经典的 gorilla/websocket 库避免一些低级 bug ,对于这种基础网络协议,不要去找那些几 kstar 的库。

测试习惯是很好的,保持。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1042394

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX