Comments (19)
这种问题请务必附上必要的信息:Go 版本,gnet 版本,OS 系统等等,不然根本无从查起;要不然就请选择 bug 的模板创建 issue
from gnet.
在eventhandler的ontraffic里主动调用gnet.Conn.Close()后然后返回gnet.Close是否会引起bug
不会,但是也不要这么做,如果是想直接关闭当前连接,那么就 return gnet.Close
,如果是想在其他的地方随时关闭连接,那么可以选择调用 gnet.Conn.Close()
,后者是并发安全且异步的,是为了让用户可以在任意地方任意时间关闭连接用的,前者是让用户可以快速直接抵关闭当前连接用的,是同步的;二者选其一就行了,没必要两个都做,但是即便是两个都做了也不会引起问题,因为内部会在关闭连接前检测其是否已经关闭,如果是则忽略掉。
在gnet的asyncwrite或者asyncwritev的回调里面,是否需要主动调用gnet.Close()呢,如果不调用是否其他地方有调用close的机会呢
我没懂你这问题,是否要关闭连接以及什么要关闭连接取决于你的需求,正如前面所说,如果你想在 event-loop 里直接关闭当前连接,那就在任意的 gnet 回调函数中 return gnet.Close
即可,如果你想在其他地方、特定的时间关闭连接,那就用 gnet.Conn.Close()
.
from gnet.
这种问题请务必附上必要的信息:Go 版本,gnet 版本,OS 系统等等,不然根本无从查起;要不然就请选择 bug 的模板创建 issue
谢谢,因为有一些具体的思路,所以也许提供一点点子就能解决了。
go: 1.20
gnet: v2.0
os: linux
现象:
压测的wsclient -> gnet实现的wsserver突然通讯,然后客户端直接选择关闭大量tcp连接, 发现服务端出现大量close_wait状态的连接
from gnet.
大量 CLOSE_WAIT
通常是服务端没有正确关闭连接导致的,如果是客户端主动关闭连接的话,gnet 会自动在服务端这边关闭对应的连接,通常不需要用户自己手动去关闭,而且会有 OnClose
回调,我建议你在这个回调里记录一下看看是否能和客户端关闭的连接数对应上。
from gnet.
在eventhandler的ontraffic里主动调用gnet.Conn.Close()后然后返回gnet.Close是否会引起bug
不会,但是也不要这么做,如果是想直接关闭当前连接,那么就
return gnet.Close
,如果是想在其他的地方随时关闭连接,那么可以选择调用gnet.Conn.Close()
,后者是并发安全且异步的,是为了让用户可以在任意地方任意时间关闭连接用的,前者是让用户可以快速直接抵关闭当前连接用的,是同步的;二者选其一就行了,没必要两个都做,但是即便是两个都做了也不会引起问题,因为内部会在关闭连接前检测其是否已经关闭,如果是则忽略掉。在gnet的asyncwrite或者asyncwritev的回调里面,是否需要主动调用gnet.Close()呢,如果不调用是否其他地方有调用close的机会呢
我没懂你这问题,是否要关闭连接以及什么要关闭连接取决于你的需求,正如前面所说,如果你想在 event-loop 里直接关闭当前连接,那就在任意的 gnet 回调函数中
return gnet.Close
即可,如果你想在其他地方、特定的时间关闭连接,那就用gnet.Conn.Close()
.
也就是说conn.Close()和return gnet.Close不会出现异常,效果一样了. asyncwrite写数据的时候,应用程序并不知道会返回什么样的错误啊,也许是连接错误了,也许是其他错误。那应用程序如何知道asyncwrite的回调里面是否应该关闭连接呢.
对于客户端直接关闭tcp连接的情况,是在eventhandler的ontraffic里收到响应,还是在onclose里时收到响应呢
from gnet.
大量
CLOSE_WAIT
通常是服务端没有正确关闭连接导致的,如果是客户端主动关闭连接的话,gnet 会自动在服务端这边关闭对应的连接,通常不需要用户自己手动去关闭,而且会有OnClose
回调,我建议你在这个回调里记录一下看看是否能和客户端关闭的连接数对应上。
头疼,。线上环境,复现不了异常情况, 当时查询的时候,是触发不了onclose回调,所以怀疑是不是ontraffic的时候触发的操作.
感谢回复
from gnet.
大量
CLOSE_WAIT
通常是服务端没有正确关闭连接导致的,如果是客户端主动关闭连接的话,gnet 会自动在服务端这边关闭对应的连接,通常不需要用户自己手动去关闭,而且会有OnClose
回调,我建议你在这个回调里记录一下看看是否能和客户端关闭的连接数对应上。
版本是v2 2.2.5是否有release修复bug呢
from gnet.
那应用程序如何知道asyncwrite的回调里面是否应该关闭连接呢.
callback 函数里有传入一个 err
,这个值会告诉你在写数据回客户端的时候是否发生了错误,你可以根据这个错误值决定要不要主动关闭连接
对于客户端直接关闭tcp连接的情况,是在eventhandler的ontraffic里收到响应,还是在onclose里时收到响应呢
不管是你主动关闭连接还是被动关闭,都会有 OnClose
回调,不会有 OnTraffic
from gnet.
大量
CLOSE_WAIT
通常是服务端没有正确关闭连接导致的,如果是客户端主动关闭连接的话,gnet 会自动在服务端这边关闭对应的连接,通常不需要用户自己手动去关闭,而且会有OnClose
回调,我建议你在这个回调里记录一下看看是否能和客户端关闭的连接数对应上。版本是v2 2.2.5是否有release修复bug呢
现在还不知道是哪里的问题,要先查清楚再说,如果只是客户端大量断开连接就能复现的话,你可以写一个简单的 demo,模拟一下那个场景,看看是否能复现,然后 debug 一下看看是哪里有问题,或者你复现之后把代码贴上来,我来 debug。
from gnet.
只能成为悬案了。因为是阿里的mse网关做的ws的代理,并不清楚他们内部的实现细节是如何实现的。如何能测试和模拟tcp断线过程在gnet中的流程呢:
- 客户端发送fin1包
- 服务端收到fin1包
- 服务端发送fin1-ack包
- 客户端crash
- 服务端发送fin2包
....
这种情况gnet可以正常处理吗,连接最终能关闭吗
from gnet.
大量
CLOSE_WAIT
通常是服务端没有正确关闭连接导致的,如果是客户端主动关闭连接的话,gnet 会自动在服务端这边关闭对应的连接,通常不需要用户自己手动去关闭,而且会有OnClose
回调,我建议你在这个回调里记录一下看看是否能和客户端关闭的连接数对应上。版本是v2 2.2.5是否有release修复bug呢
现在还不知道是哪里的问题,要先查清楚再说,如果只是客户端大量断开连接就能复现的话,你可以写一个简单的 demo,模拟一下那个场景,看看是否能复现,然后 debug 一下看看是哪里有问题,或者你复现之后把代码贴上来,我来 debug。
我们自己写的demo或者压测环境一切ok, 中间经过阿里mse的代理后出现了异常.咨询过他们网关的负责人,ws代理的时候是直接关闭tcp连接.
from gnet.
ws代理的时候是直接关闭tcp连接.
这是什么意思?什么时候 MSE 会直接关闭 TCP 连接?
from gnet.
ws代理的时候是直接关闭tcp连接.
这是什么意思?什么时候 MSE 会直接关闭 TCP 连接?
wsclient -> mse ws代理 -> wsserver
wsclient 直接ctrl + c 异常结束, mse直接关闭对上游服务的tcp连接. 主要是close_wait恢复不了,几个小时了,都还是大量的close_wait
from gnet.
CLOSE_WAIT
就是服务端没有主动 close
掉连接导致的,这种情况可能是你的 gnet server 没有正确感知到对端的连接断开事件,但这并不应该发生,gnet 是有做正确处理的,你也说了在测试环境没有用代理是没有问题的,感觉还是代理的问题,你能不能在测试环境也搞一个 MSE 然后再 debug 一下呢?
from gnet.
CLOSE_WAIT
就是服务端没有主动close
掉连接导致的,这种情况可能是你的 gnet server 没有正确感知到对端的连接断开事件,但这并不应该发生,gnet 是有做正确处理的,你也说了在测试环境没有用代理是没有问题的,感觉还是代理的问题,你能不能在测试环境也搞一个 MSE 然后再 debug 一下呢?
我本地配置好环境试试。另外发现的一个可疑的点是这样,reuseport选项是否可能导致close_wait呢,如果大量的tcp连接频繁创建销毁
from gnet.
reuseport 可以用来强制重用还处于 TIME_WAIT
的连接,但通常不推荐这么搞,而且和 CLOSE_WAIT
没什么关系。
from gnet.
reuseport 可以用来强制重用还处于
TIME_WAIT
的连接,但通常不推荐这么搞,而且和CLOSE_WAIT
没什么关系。
查看了一下gnet的源码,不太确定是不是某些条件下判断出现的bug:
// eventloop_unix.go
func (el *eventloop) close(c *conn, err error) (rerr error) {
if addr := c.localAddr; addr != nil && strings.HasPrefix(c.localAddr.Network(), "udp") {
rerr = el.poller.Delete(c.fd)
if c.fd != el.ln.fd {
rerr = unix.Close(c.fd)
el.connections.delConn(c)
}
if el.eventHandler.OnClose(c, err) == Shutdown {
return errorx.ErrEngineShutdown
}
c.release()
return
}
if !c.opened || el.connections.getConn(c.fd) == nil {
return // ignore stale connections
}
// Send residual data in buffer back to the peer before actually closing the connection.
if !c.outboundBuffer.IsEmpty() {
for !c.outboundBuffer.IsEmpty() {
iov := c.outboundBuffer.Peek(0)
if len(iov) > iovMax {
iov = iov[:iovMax]
}
if n, e := io.Writev(c.fd, iov); e != nil {
el.getLogger().Warnf("close: error occurs when sending data back to peer, %v", e)
break
} else { //nolint:revive
_, _ = c.outboundBuffer.Discard(n)
}
}
}
err0, err1 := el.poller.Delete(c.fd), unix.Close(c.fd)
if err0 != nil {
rerr = fmt.Errorf("failed to delete fd=%d from poller in event-loop(%d): %v", c.fd, el.idx, err0)
}
if err1 != nil {
err1 = fmt.Errorf("failed to close fd=%d in event-loop(%d): %v", c.fd, el.idx, os.NewSyscallError("close", err1))
if rerr != nil {
rerr = errors.New(rerr.Error() + " & " + err1.Error())
} else {
rerr = err1
}
}
el.connections.delConn(c)
if el.eventHandler.OnClose(c, err) == Shutdown {
rerr = errorx.ErrEngineShutdown
}
c.release()
return
}
func (c *conn) release() {
c.ctx = nil
c.localAddr = nil
c.remoteAddr = nil
c.buffer = nil
if addr, ok := c.localAddr.(*net.TCPAddr); ok && c.localAddr != c.loop.ln.addr && len(addr.Zone) > 0 {
bsPool.Put(bs.StringToBytes(addr.Zone))
}
if addr, ok := c.remoteAddr.(*net.TCPAddr); ok && len(addr.Zone) > 0 {
bsPool.Put(bs.StringToBytes(addr.Zone))
}
c.pollAttachment.FD, c.pollAttachment.Callback = 0, nil
if !c.isDatagram {
c.opened = false
c.peer = nil
c.inboundBuffer.Done()
c.outboundBuffer.Release()
}
}
在发生异常的情况下,比如,第一次调用close方法,
err0, err1 := el.poller.Delete(c.fd), unix.Close(c.fd)
err0执行成功,err1返回的错误是unix.EAGAIN(假设是系统中断引起的),然后执行c.release()将c.opened设置为false,第二次执行close方法的时候,
if !c.opened || el.connections.getConn(c.fd) == nil {
return // ignore stale connections
}
没有close的机会了.
是否需要在应用中自己处理err为unix.EAGAIN的这种错误
from gnet.
系统调用 close()
不会返回 EAGAIN
,最多返回 EINTR
,但是这种概率微乎其微,所以在实践中基本上不会专门去处理这种情况,而且就算真的出现这种情况,日志会打印 error occurs in event-loop: %v
,你有看到这个日志吗?而且这种情况发生的概率太小了,就算真的有,也应该是极少数,怎么可能有大量的 close()
调用在短时间内都发生了 EINTR
错误, Linux 不至于这么不稳定,以前也没有别人反馈过使用 gnet
遇到过这种情况,我觉得不可能是这里的问题。
from gnet.
系统调用
close()
不会返回EAGAIN
,最多返回EINTR
,但是这种概率微乎其微,所以在实践中基本上不会专门去处理这种情况,而且就算真的出现这种情况,日志会打印error occurs in event-loop: %v
,你有看到这个日志吗?而且这种情况发生的概率太小了,就算真的有,也应该是极少数,怎么可能有大量的close()
调用在短时间内都发生了EINTR
错误, Linux 不至于这么不稳定,以前也没有别人反馈过使用gnet
遇到过这种情况,我觉得不可能是这里的问题。
https://www.man7.org/linux/man-pages/man2/close.2.html
确实如此没有err.dragin. 看手册里是推荐出现EINTR错误时,推荐重试关闭文件描述符.
好像没有给gnet添加日志库.没有看到上面的日志
from gnet.
Related Issues (20)
- [Feature]: 实现异步非阻塞的PacketConn接口,从而支持quic协议 HOT 2
- [Bug]: windows下的实现似乎有bug HOT 2
- [Question]: Does gnet support a websocket server that can handle different URL patterns HOT 1
- [Question]: 请问 多网卡情况下,在 udp 的 OnTraffic 事件里面,怎么得到接收数据的网络接口呢 HOT 1
- [Question]: 请教运行在serverless中http的Keep-Alive应该如何配置 HOT 2
- [Question]: 数据超过65535时多次触发OnTraffic如何处理数据? HOT 2
- [Question]: 重启gnet.server需要如何做? HOT 6
- [Question]: 请问作者是否有异步读取的最佳实践示例呢? HOT 1
- [Question]:自定义codec中是否会存在接受header失败导致后续数据都无法正确获取的情况 HOT 1
- [Feature]: 添加pool来管理asyncwritev的内存, 以及客户端的api是否可以独立于服务端 HOT 7
- [Question]: IO Wait如何解决 HOT 3
- [Question]: conn_map.go:66 panic concurrent map read and map write HOT 2
- [Question]: 可疑的CPU占用 HOT 8
- [Question]: gnet打印很多error occurs in user-defined function, use of closed network connection HOT 1
- 哥 client 的使用好复杂啊 HOT 3
- [Question]: Server端回包立刻关闭连接,OnTraffic 收不到最后一个包的数据 HOT 11
- [Question]: ReadFrom系列函数的作用 HOT 1
- [Feature]: Support for SO_BINDTODEVICE? HOT 4
- 一条链接往外写数据,内存增长很快。 HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gnet.