NXP MCU 技术论坛
直播中

陈韵瑄

7年用户 988经验值
私信 关注
[问答]

LWIP connect() 失败并显示 -1和errno 128的原因?

我遇到了一个使用 LWIP 通过 WiFi 连接到远程主机时发生的问题。在从深度睡眠或冷启动唤醒后,它似乎每隔几个传输周期随机发生一次。

connect()返回的error为-1,errno为128,表示socket未连接。

激活 LWIP 调试输出后,在 lwip_connect 触发的初始连接序列期间会出现以下错误:
代码:全选
ip4_route: No route to 91.121.93.94
lwip_connect(54) failed, err=-4

此错误解析为 ERR_RTE(“路由问题”)。

该消息重复了一段时间,连接尝试最终失败,错误代码为 -15,表示连接已关闭。

tcp_slowtmr: processing active PCB
tcp_slowtmr: max SYN retries reached
tcp_pcb_purge
tcp_pcb_purge: data left on ->unacked
pbuf_free(0x3fccbc5c)
pbuf_free: deallocating 0x3fccbc5c
lwip_connect(54, addr=91.121.93.94 port=8883)
lwip_connect(54) failed, err=-15

据我了解,无法收到对 SYN 请求的答复。

所有后续连接到所述主机的努力都会导致相同的错误模式,除了触发重启或命令设备进入深度睡眠。

连接例程按以下方式使用:

代码:全选
commdev::errlvl_t esp32s3_wifi::socket_connect(unsigned int sock_id, const commdev::socket_connection_t &socket_connection) {
    sockaddr_in addr;
    int ret;

    auto conn = socket_connection;

    if (!conn.addr_remote.size()) {
        std::stringstream ss;
        ss << "no remote given";
        LOG_FULL_ERROR(ss.str());

        return commdev::E_ERR;
    }

    memset(&addr, 0, sizeof(sockaddr_in));

    ip_addr_t target_addr;
    struct addrinfo hint;
    struct addrinfo *res = NULL;
    memset(&hint, 0, sizeof(hint));
    memset(&target_addr, 0, sizeof(target_addr));

    int get_res = getaddrinfo(conn.addr_remote.c_str(), std::to_string(conn.port_remote).c_str(), &hint, &res);

    if (0 != get_res || NULL == res) {
        std::stringstream ss;
        ss << "getaddrinfo() failed for \"" << conn.addr_remote << "\". Result: " << errno << ", addr_info:" << res << ", errno:" << errno;
        LOG_FULL_ERROR(ss.str());

        if (res) {
            freeaddrinfo(res);
        }

        error(NL_SOCKET_ADDR_RES_ERROR);
        error_extended(errno);
        return commdev::E_ERR;
    }

    struct in_addr addr4 = ((struct sockaddr_in*) (res->ai_addr))->sin_addr;
    inet_addr_to_ip4addr(ip_2_ip4(&target_addr), &addr4);
    freeaddrinfo(res);

    std::string s_host_res;

    {
        char str[INET_ADDRSTRLEN];

        inet_ntop(AF_INET, &addr4, str, INET_ADDRSTRLEN);

        s_host_res = std::string(str);
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons((unsigned short )conn.port_remote);
    addr.sin_addr.s_addr = inet_addr(s_host_res.c_str());

    {
        std::stringstream ss;
        ss << "Connecting to " << conn.addr_remote << " [" << s_host_res << "]@" << conn.port_remote;
        LOG_FULL_INFO(ss.str());
    }

    psense::os::core::timer tim_conn(120s);

    while (!tim_conn.is_timeout()) {
        ret = ::connect(m_sockfd, (struct sockaddr*) &addr, sizeof(addr));

        if (ret != 0) {
            if (EINPROGRESS == errno || EAGAIN == errno) {
                std::this_thread::sleep_for(100ms);
                continue;
            } else if (EHOSTUNREACH == errno) {
                LOG_FULL_DEBUG("EHOSTUNREACH");

                std::this_thread::sleep_for(100ms);
                continue;
            } else if (EISCONN == errno || EALREADY == errno) {
                // test if socket is writable and 3 way handshake completed
                struct timeval timeout;
                fd_set writing;

                /* initialize the bit sets */
                FD_ZERO(&writing);

                /* add r, w, and e to the appropriate bit set */
                FD_SET(m_sockfd, &writing);

                memset(&timeout, 0, sizeof(timeout));

                int rc = select(m_sockfd + 1, NULL, &writing, NULL, &timeout);

                if (rc < 0) {
                    /* an error occurred during the select() */
                    LOG_FULL_ERROR("select error");
                } else if (rc == 0) {
                    /* none of the sockets were ready in our little poll */
                    LOG_FULL_ERROR("socket not ready\n");
                } else {
                    /* at least one of the sockets is ready */
                    if (FD_ISSET(m_sockfd, &writing)) {
                        LOG_FULL_INFO("Socket ready");
                        break;
                    } else {
                        LOG_FULL_ERROR("Socket not ready");
                    }

                }

                std::this_thread::sleep_for(100ms);
                continue;
            }

            std::stringstream ss;
            ss << "connect() failed. Ret = " << ret << ", errno: " << errno;
            LOG_FULL_ERROR(ss.str());

            error(NL_SOCKET_CONNECT_ERROR);
            error_extended(errno);

            return commdev::E_ERR;
        } else {
            break;
        }

    }

    if (tim_conn.is_timeout()) {
        LOG_FULL_ERROR("Timeout");
        return commdev::E_ERR;
    }

    LOG_FULL_INFO("Connected");

    error(NL_NO_ERROR);
    error_extended(NL_NO_ERROR);

    return commdev::E_OK;
}

我附上了激活 LWIP_DEBUG 的序列日志。

这种行为的原因可能是什么,可以采取什么措施来规避它?

更多回帖

发帖
×
20
完善资料,
赚取积分