Android中的Linux套接字连接失败

Android中的Linux套接字连接失败,android,linux,sockets,Android,Linux,Sockets,我想用NDK在Android中创建一个套接字,但有时在连接到服务器时会出现一些错误,我可以确保用户的手机网络可用。 一种情况是超时错误,另一种情况似乎是连接被拒绝,因为我得到了以下日志,我认为第二种错误是连接被拒绝,因为getsockopt的错误是111,即使strerror现在正在给我操作,但服务器地址是有效的: connect::socket error: Operation now in progress Or connect::error:111, Operation now in

我想用NDK在Android中创建一个套接字,但有时在连接到服务器时会出现一些错误,我可以确保用户的手机网络可用。 一种情况是超时错误,另一种情况似乎是连接被拒绝,因为我得到了以下日志,我认为第二种错误是连接被拒绝,因为
getsockopt
的错误是111,即使
strerror
现在正在给我操作,但服务器地址是有效的:

connect::socket error: Operation now in progress 
Or 
connect::error:111, Operation now in progress
以下是我的代码片段:

bool connect(int sockfd, struct sockaddr *address, socklen_t address_len, int timeout) {
    int ret = 0;
    struct timeval tv;
    fd_set mask;

    // set socket non block
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    // use select to check socket connection
    ret = connect(sockfd, address, address_len);
    if (-1 == ret) {
        if (errno != EINPROGRESS) {
            perror("connect");
            inetConnectFailCode = errno;
            LOG(TAG.c_str(), "connect::errno != EINPROGRESS: %s", strerror(errno));
            return false;
        }
        LOG(TAG.c_str(), "connecting...\n");

        FD_ZERO(&mask);
        FD_SET(sockfd, &mask);
        tv.tv_sec = timeout;
        tv.tv_usec = 0;

        if (select(sockfd + 1, NULL, &mask, NULL, &tv) > 0) {
            int error = 0;
            socklen_t tmpLen = sizeof(int);
            int retopt = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &tmpLen);
            if (retopt != -1) {
                if (0 == error) {
                    LOG(TAG.c_str(), "has connect");
                    return true;
                } else {
                    //I get error here
                    LOG(TAG.c_str(), "connect::error:%d, %s", error, strerror(errno));
                    return false;
                }
            } else {
                LOG(TAG.c_str(), "connect::socket error:%d", error);
                return false;
            }
        } else {
            //timeout, and I get error here sometimes
            LOG(TAG.c_str(), "connect::socket error: %s", strerror(errno));
            return false;
        }
    }
    LOG(TAG.c_str(), "has connect");
    return true;
}
这个问题困扰了我很长时间,任何人都可以帮我一个忙,谢谢您的帮助。

您显示了错误的错误消息。 如果
getsockopt(SO_ERROR)
失败,即使它没有有效值,也会输出
ERROR
。但是,更重要的是,如果
getsockopt(SO_ERROR)
成功,但
ERROR
不是0,则将
errno
传递到
strerror()
而不是传递
ERROR
errno
仍然是从最初失败的
connect()
调用开始的
EINPROGRESS
,因此您的错误消息显示
“操作正在进行”
。错误111是
ECONNREFUSED
,这将是
“连接被拒绝”

另外,如果
select()
返回,则显示错误的错误消息。 如果
getsockopt(SO_ERROR)
失败,即使它没有有效值,也会输出
ERROR
。但是,更重要的是,如果
getsockopt(SO_ERROR)
成功,但
ERROR
不是0,则将
errno
传递到
strerror()
而不是传递
ERROR
errno
仍然是从最初失败的
connect()
调用开始的
EINPROGRESS
,因此您的错误消息显示
“操作正在进行”
。错误111是
ECONNREFUSED
,这将是
“连接被拒绝”


另外,如果
select()
返回感谢,但您发布的原因可能不会发生,因为要连接的服务器是IM服务器,它会连续工作,我们没有发现任何异常情况。此应用的其他网络请求(不是到IM服务器)是正常的,这会使它更加混乱。@wqycsu您收到一个
ETIMEDOUT
(110)或
econnrefered
(111)错误。在
connect()
期间,无论您连接到的服务器类型如何,这些错误都有几种可能发生。1)您连接到错误的IP/端口,或者它没有侦听连接;2)服务器太忙,无法在此时接受连接;或者3)连接被防火墙/路由器阻止。谢谢,但您发布的原因可能不会发生,因为要连接的服务器是IM服务器,它会连续工作,我们没有发现任何例外情况。此应用的其他网络请求(不是到IM服务器)是正常的,这会使它更加混乱。@wqycsu您收到一个
ETIMEDOUT
(110)或
econnrefered
(111)错误。在
connect()
期间,无论您连接到的服务器类型如何,这些错误都有几种可能发生。1)您连接到错误的IP/端口,或者它没有侦听连接;2)服务器太忙,无法在此时接受连接;或者3)连接被防火墙/路由器阻止。
bool connect(int sockfd, struct sockaddr *address, socklen_t address_len, int timeout) {
    // set socket non block
    int flags = fcntl(sockfd, F_GETFL, 0);
    fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

    // use select to check socket connection
    int ret = connect(sockfd, address, address_len);
    if (-1 == ret) {
        int error = errno;
        if (EINPROGRESS == error) {
            LOG(TAG.c_str(), "connecting...\n");

            fd_set mask;
            struct timeval tv;

            FD_ZERO(&mask);
            FD_SET(sockfd, &mask);

            tv.tv_sec = timeout;
            tv.tv_usec = 0;

            ret = select(sockfd + 1, NULL, &mask, NULL, &tv);
            if (0 < ret) {
                socklen_t tmpLen = sizeof(int);
                ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &tmpLen);
                if (-1 == ret) {
                    error = errno;
                }
            } else if (0 == ret) {
                error = ETIMEDOUT;
            } else {
                error = errno;
            }
        }

        if (0 != error) {
            inetConnectFailCode = error;
            LOG(TAG.c_str(), "connect::error:%d, %s", error, strerror(error));
            return false;
        }
    }

    LOG(TAG.c_str(), "has connect");
    return true;
}