Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

当socket发生错误时,关闭了socket,却没有回调onclose方法 #1373

Closed
iwifigame opened this issue Apr 5, 2021 · 9 comments
Closed

Comments

@iwifigame
Copy link

No description provided.

@cloudwu
Copy link
Owner

cloudwu commented Apr 5, 2021

出错和正常关闭是两个事件。你需要在出错时主动调用 socket.close ,这样才会收到 close 事件。

@cloudwu
Copy link
Owner

cloudwu commented Apr 5, 2021

我明白了。因为历史遗留,有些出错处理在 c 层调用了 force_close 导致后续主动 close 未能触发关闭事件。这里我明天改一下。

另外,问一下这里的 socket 出错指的的什么错误?出错信息是什么?

@iwifigame
Copy link
Author

我明白了。因为历史遗留,有些出错处理在 c 层调用了 force_close 导致后续主动 close 未能触发关闭事件。这里我明天改一下。

另外,问一下这里的 socket 出错指的的什么错误?出错信息是什么?

是在forward_message_tcp里。错误信息是: socket: error on 99 Connection reset by peer

cloudwu added a commit that referenced this issue Apr 6, 2021
@cloudwu
Copy link
Owner

cloudwu commented Apr 6, 2021

此处不应该 force_close ,因为即使 Connection reset by peer ,只表明不可以写(对方半关闭),但还是可以读的。

最后一次提交修正了这个问题,删除了 force_close,这样后续主动关闭 fd 就会产生 SOCKET_CLOSE 了。试试看?

目前在 https://github.com/cloudwu/skynet/blob/master/lualib/skynet/socket.lua#L159 主动 shutdown 了 fd ,这会导致不再能读。这点以后会考虑去掉。之所以在遇到 error 就主动关闭,是考虑到兼容 skynet 旧版本的行为(遇到错误自动关闭),避免泄露 fd 。

@iwifigame
Copy link
Author

iwifigame commented Apr 6, 2021

用的最新的代码。在forward_message_tcp里,错误信息是: socket: error on 99 Connection reset by peer。还是出现。出现的机率没有以前大,还是没有调用onclose。

@cloudwu
Copy link
Owner

cloudwu commented Apr 6, 2021

你在对方关闭“读”后继续写一定会产生 “Connection reset by peer” ,这是正常的。

出错后没有产生 SOCKET_CLOSE 吗?现在产生 SOCKET_CLOSE 有两种情况之一:

  1. 对方关闭"写" ,继而我方 read 到 0 。
  2. 我方主动关闭 fd 。

注:SOCKET_ERR 有可能晚于 SOCKET_CLOSE 收到,即 onclose 可能先发生,然后再触发错误事件。

之前之所以没有产生 SOCKET_CLOSE 是因为调用了 force_close 把 fd 删除了,导致以上情况 2 发生的时候, fd 已经不存在,所以就不再产生这个事件。修改之后,在发生 “Connection reset by peer” 时,https://github.com/cloudwu/skynet/blob/master/lualib/skynet/socket.lua#L159 的 driver.shutdown 就会主动关闭 fd (2) ,然后应该发出 SOCKET_CLOSE 事件。

你看看在 https://github.com/cloudwu/skynet/blob/master/skynet-src/socket_server.c#L1134 close_socket 函数中加一些 log ,看看在什么地方返回了 -1 而没有返回 SOCKET_CLOSE

close_socket 中有三处可能返回 -1 的地方:

其一,就是之前修正的地方,如果调用了 force_close 那么 socket_invalid 会返回真,导致这里不产生 SOCKET_CLOSE 。
其二和三均为 shutdown_read 为真的情况,即之前已经调用过 close_read ,曾经返回过 SOCKET_CLOSE 。

@cloudwu
Copy link
Owner

cloudwu commented Apr 6, 2021

我尝试写个测试来触发 onclose 没调用的情况,没能成功。

不过发现了一处 poll 循环中处理 eof 事件的小 bug (最近的提交中修正),我认为修复的问题和这里漏掉 onclose 无关。

@iwifigame
Copy link
Author

发生上面情况的原因大概如下:
当socket fd发生错误时,socket.lua的SKYNET_SOCKET_TYPE_ERROR处理中,会把s.connected = false设置成false。

然后,由于在应用层主动调用了socket.close,来关闭上面的socket fd(并不知道是发生了错误,只是由于有两个socket fd是关联的,当另一个fd不可用时,应该层主动关闭的。因此会出现随机出现的现象)。 而在socket.close调用中,会把socket_pool[id] = nil 设置成nil。

然后在SKYNET_SOCKET_TYPE_CLOSE的处理中,由于s为nil,不会再走到on_close那里。

@cloudwu
Copy link
Owner

cloudwu commented Apr 7, 2021

我今天把 onclose 的 callback 放在外面,应该能解决这个倒序的问题。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants