stephane / libmodbus

A Modbus library for Linux, Mac OS, FreeBSD and Windows
http://libmodbus.org
GNU Lesser General Public License v2.1
3.52k stars 1.77k forks source link

modbus-tcp协议:ERROR Resource temporarily unavailable #724

Closed ssgnh closed 1 month ago

ssgnh commented 12 months ago

您好,我在使用modbus tcp协议写客户端程序,客户端会不停的向服务端发送请求数据。

设置了modbus_set_error_recovery(ctx, MODBUS_ERROR_RECOVERY_LINK | MODBUS_ERROR_RECOVERY_PROTOCOL);

当我将网线拔掉时,调试信息显示 timeout select类似的信息,这是正常的,但是断开网线一段时间后,就会报ERROR Resource temporarily unavailable。调试发现是在执行modbus_read_registers 函数会报此错误。

我在libmodbus源码里调试了下,发现在tcp正常连接中,拔掉网线,程序并没有检测到链路断开(errno)来重新建立连接,而是一直在modbus_flush,然后继续发送,然后就报了Resource temporarily unavailable错误,不知道这样理解是否正确,期待您的回复

  do {
        rc = ctx->backend->send(ctx, msg, msg_length);
        if (rc == -1) {
            _error_print(ctx, NULL);
            if (ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) {
#ifdef _WIN32
                const int wsa_err = WSAGetLastError();
                if (wsa_err == WSAENETRESET || wsa_err == WSAENOTCONN ||
                    wsa_err == WSAENOTSOCK || wsa_err == WSAESHUTDOWN ||
                    wsa_err == WSAEHOSTUNREACH || wsa_err == WSAECONNABORTED ||
                    wsa_err == WSAECONNRESET || wsa_err == WSAETIMEDOUT) {
                    modbus_close(ctx);
                    _sleep_response_timeout(ctx);
                    modbus_connect(ctx);
                } else {
                    _sleep_response_timeout(ctx);
                    modbus_flush(ctx);
                }
#else
                int saved_errno = errno;

                if ((errno == EBADF || errno == ECONNRESET || errno == EPIPE)) {
                    modbus_close(ctx);
                    _sleep_response_timeout(ctx);
                    modbus_connect(ctx);
                } else {
                    _sleep_response_timeout(ctx);
                    modbus_flush(ctx);
                }
                errno = saved_errno;
#endif
            }
        }
    } while ((ctx->error_recovery & MODBUS_ERROR_RECOVERY_LINK) && rc == -1);
ssgnh commented 12 months ago

我又换个例子测试了下,发现,在正常连接成功后,断开网线,‘rc = ctx->backend->send(ctx, msg, msg_length)’返回有值,即使断线了还是正常返回发送字节数,持续了一两分钟后,报Resource temporarily unavailable错误,再过段时间,线程好像就卡住了,或者是死掉了(没写检测线程程序,不知道是不是挂掉了),线程循环里的打印程序就不打印了。查了下,应该是socket 发送缓冲区,应该怎么解决