socket 释放失败

2022-11-11 09:53:26 +08:00
 lestly

我自己用 epoll 写了一个客户端程序,然后跑起来时发现有个别连接断开后,句柄一直无法释放,但是我看日志,那个句柄是有被 shutdown ,close 的,close 的返回值是 0 ,并且也不存在多线程的问题。想问问大佬们有什么思路吗?

1700 次点击
所在节点    Linux
11 条回复
Mohanson
2022-11-11 10:02:36 +08:00
netstat 看下是不是有 TCP 链接在 FIN-WAIT2 状态, 有的话就是你客户端 /服务端其中一方没有正确调用 Close().
oceanthe1h
2022-11-11 10:11:25 +08:00
使用 close 函数的话,对于一个 socket ,如果引用大于 1 则引用减 1 ,否则发送 FIN 关闭 TCP 连接。epoll 可能有父子进程的场景,例如父进程打开了 socket ,然后用派生子进程来处理业务,父进程继续对网络请求进行监听,永远不会终止。客户端发 FIN 过来的时候,处理业务的子进程的 read 返回 0 ,子进程发现对端已经关闭了,直接调用 close 对本端进行关闭。实际上,仅仅使 socket 的引用计数减 1 ,socket 并没关闭。从而导致系统中又多了一个 CLOSE_WAIT 的 socket
liqinliqin
2022-11-11 10:19:58 +08:00
可以试试 swoole ,这个方便又快
lestly
2022-11-11 10:24:46 +08:00
@Mohanson 我明白了
lestly
2022-11-11 10:28:55 +08:00
@oceanthe1h 我的这个程序应该不存在父子进程这个场景,不过我会留意一下你说的这个点
lestly
2022-11-11 10:29:28 +08:00
@liqinliqin 可能嵌入式设备并不支持这个
liqinliqin
2022-11-11 10:31:05 +08:00
你这个要贴出来代码,看底层是不是 lwip 库,句柄不能释放是不可能的,你应该是读或是阻塞了,没有走到关闭这个代码。
ysc3839
2022-11-11 10:45:44 +08:00
@lestly 啥设备? C++总该支持吧?支持的话试试 asio ?
lestly
2022-11-11 18:00:14 +08:00
@liqinliqin 能确定执行了 close ,因为加了打印。但是在 /proc/pid/fd 却看到句柄还被占用着
tomychen
2022-11-12 14:22:57 +08:00
https://idea.popcount.org/2017-03-20-epoll-is-fundamentally-broken-22/

正常来讲,需要先把 fd 从 epoll 中移出再 close()

不然的话,用户态的 fd 确实执行了 close 动作,但 epoll 还在 hold 着

看看是不是这个问题
lestly
2022-11-18 10:06:20 +08:00
@tomychen 多谢,我又学到一点

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

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

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

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

© 2021 V2EX