客户端断开连接后,我是不是必须关闭服务器端的套接字?
Posted
技术标签:
【中文标题】客户端断开连接后,我是不是必须关闭服务器端的套接字?【英文标题】:Do I have to close the socket on the server side after client disconnects?客户端断开连接后,我是否必须关闭服务器端的套接字? 【发布时间】:2017-09-08 04:45:41 【问题描述】:所以让我简化我正在处理的代码:
int fd = socket(...);
int client = accept(fd, ...);
while (true)
int bytes_read = recv(client, ...);
if (bytes_read == 0)
break;
;
此时我已经知道客户端已断开连接(recv
返回 0)。但是我还需要打电话吗
close(client);
?
【问题讨论】:
好吧,我认为您需要这样做,因为 [我认为] 由于您没有关闭文件描述符,因此会造成内存泄漏。 如果你不调用 close(),并继续创建新的套接字(例如通过 accept()),那么最终你的进程的套接字表将被剩余的套接字填满,然后你的进程就赢了'不能再创建了,所以accept()、socket()等都会因为errno=EMFILE而失败,然后你的程序就不能再正常工作了:( 【参考方案1】:是的。
当您recv()
0 字节时,这是内核让您知道远程主机已关闭其发送 端连接的方式。他们可能仍然打开套接字并且可以接收您发送的更多数据(但不回复)。
当您在 TCP 套接字上调用 close()
时,您正在做两件事:
-
关闭套接字的本地端,让远程主机知道您也已完成传输。如果不这样做,您可能会让客户端挂起,等待您发送更多数据。
关闭文件描述符。这将释放进程打开文件表中的条目。如果不这样做,您会浪费资源,并且可能会发现自己的内存或可用文件描述符不足。大多数操作系统都对进程一次可以打开的文件描述符(或句柄)的数量有硬性限制。
【讨论】:
Ad1:不需要通知客户端(远程主机)(它已经死了),但需要释放连接表中的条目(它可能会先停留一段时间-wait state for some time) 这会在你的 (2) 中自动处理:它是通过 close(fd) 处理的 @wildplasser 回复:1 我认为你错过了我的观点。客户端可能没有“死”——他可能只调用了shutdown(fd, SHUT_WR)
,并且可能仍在等待来自服务器的更多数据。在这种情况下,他确实需要被告知。
没错;它可能是半封闭的。但我完全同意你的看法:调用 close(fd) 是要走的路。
@Jonathon 收到 EOF,调用关闭是没有意义的,因为对方已经关闭了连接或至少关闭了连接的发送部分。调用 shutdown() 将关闭连接的另一半,就像 close() 无论如何都会做的那样。关于“需要被告知”,close() 也会发生这种情况,无需调用 shutdown()。
谢谢@Meixner,但是为什么那个评论是针对我的呢?我很清楚close()
意味着shutdown()
。我没有建议需要致电shutdown
。【参考方案2】:
您需要关闭描述符以释放绑定到它的资源。
【讨论】:
【参考方案3】:答案是肯定的。原因是 accept() 分配内存, close() 释放内存。
想象一个理论上的情况,您的代码处于循环中,并且每次调用 accept() 时,它都会分配 1GB 的 RAM(假设它是一个非常低效的套接字库 :-))。每当您调用 close() 时,它都会释放 1GB 的 RAM。如果你从不调用 close(),那么在你用完内存之前,循环会发生多少次 accept()?
当然,accept() 只分配一小块内存,但最终你会耗尽内存,除非你对它做点什么。
【讨论】:
内存本身并没有真正通过问题。打开文件描述符的限制会咬你。我认为您需要重新表述您的答案,因为不清楚这句话是假设性的:“每次调用 accept(),它都会分配 1GB 的 RAM。”以上是关于客户端断开连接后,我是不是必须关闭服务器端的套接字?的主要内容,如果未能解决你的问题,请参考以下文章
如何检查客户端是不是通过 C++ 中的 Winsock 断开连接?
如何在socket.io中的断开事件上获取断开连接的客户端的套接字ID
Winsock - 客户端断开连接,关闭套接字循环/最大连接数