c - 检测断开的客户端套接字连接(跨平台适用性)

标签 c sockets tcp network-programming client-server

我知道这个问题有数百个答案,但就我的情况而言,我无法完成。场景是这样的,我们有一个用TCP/IP协议(protocol)写的服务器,我们有多个客户端连接到这个服务器上。这里的客户端是一个软件模块,它在客户端机器上启动之前,在服务器上注册它的存在并加载功能。但问题是这个软件模块崩溃了,并且没有 socket.close() 被调用,这将使得它的足迹仍然存在于服务器中,即使它崩溃了。如何识别?

我在客户端使用 select() 方法来通知来自客户端和服务器的任何信息(反之亦然) 我无法在服务器中为每个客户端请求单独创建一个进程,也无法在客户端机器中创建父子机制。 tcp-keepalive 不适用,因为我们需要在 Windows 中调整注册表?我需要一个 x 平台兼容的解决方案。 我已经读到 recv() 到服务器代码中连接的套接字将从“那个”客户端返回一些值,例如 0 表示套接字已关闭?我可以用它来清除服务器数据库中的客户端套接字注册吗?这行得通吗?

最佳答案

您没有指定在服务器端代码中使用什么方法来处理套接字事件。无论您使用何种方法轮询套接字,recv()将返回 0 或可能 -1/SOCKET_ERROR当客户端崩溃时。

为了检测不活动的客户端连接,大多数服务器应用程序会在应用程序层协议(protocol)中定期发送某种形式的心跳或 ping 消息。当无法从客户端发送 ACK 时,服务器应用程序将通过 recv() 收到客户端断开连接的通知。返回 0 或 SOCKET_ERROR错误代码类似于 WSAENETRESET , WSAECONNABORTED , WSAETIMEDOUT , 或 WSAECONNRESET (请参阅各种错误代码 here )。通常在服务器将心跳发送到不再事件的客户端 TCP 端口后,会发送一个 ICMP 数据包作为响应,提醒您的服务器端口或主机不活动(recv() 将立即通知您此事件)。

如果你想打开 TCP 保持事件计时器,你可以使用套接字选项 SO_KEEPALIVE .也可以使用 SIO_KEEPALIVE_VALS 设置间隔.

编辑:请记住各种错误代码和选项 SIO_KEEPALIVE_VALS 是特定于 Win32 的。要为其他操作系统处理这些事件,您将需要使用操作特定的方法来检索错误代码并设置 TCP 保持事件间隔(如果您选择这样做)。保持您的代码跨平台兼容的最佳建议是简单地将应用层心跳消息实现到您的协议(protocol)或其他一些应用层特定的超时中。这样做会让您忘记管理 TCP keep alives。

更新

我无法对 EJP 的回答发表评论,但重要的是要通过调用 send() 指出这一点他有效地建议您在协议(protocol)的应用层中实现心跳/ping 消息。在检查 send() 的返回值时很重要,如果您正在轮询/选择读取事件,您将在调用 recv() 时立即收到 TCP 连接断开的通知。 TCP 堆栈认为连接断开的那一刻。如果您等待应用程序计时器尝试使用 send() 发送一些数据在 recv() 之后可能有很多秒(取决于您的间隔计时器的长度)已经通知您连接已断开。换句话说:注意 recv()返回值以及您的 send()返回值。

关于c - 检测断开的客户端套接字连接(跨平台适用性),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38366151/

相关文章:

linux - 如何从 Windows 10 主机访问 Linux Docker 容器的 TCP 端口

c - 并非每个单元格都已填充时打印数组

c - 查找出现频率、最小最大而不存储输入

c - 如何找到指向字符串的指针数组的新大小

macOS SO_REUSEPORT 的setsockopt()

php - 如何使用终端/PHP 测试 PHP 套接字 TCP/IP 服务器?

c - Openwrt内核模块

python - 使用Socket进行Python UDP通信,检查收到的数据

Java套接字服务器和客户端

android - 无法通过 TCP/IP 连接 Android ADB