gpt4 book ai didi

android - Android 中的 Linux 套接字连接失败

转载 作者:太空宇宙 更新时间:2023-11-04 09:12:19 26 4
gpt4 key购买 nike

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

connect::socket error: Operation now in progress 
Or
connect::error:111, Operation now in progress

这是我的代码 fragment :

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( ) 而不是传递 errorerrno 仍然是 EINPROGRESS 来自最初失败的 connect() 调用,因此您的错误消息显示 “Operation now in progress”。错误 111 是 ECONNREFUSED,它应该是 "Connection refused"

此外,如果 select() 返回 <= 0,则无论 select() 实际返回什么,您都将输出 strerror(errno) . errno 只有在 select() 返回 -1 的情况下才有效。如果 select() 返回 0,则不能保证更新 errno

尝试更像这样的东西:

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;
}

话虽如此,如果服务器机器可以访问并收到您的连接请求,您可能会收到一个 ECONNREFUSED 错误,但主动拒绝它是因为它当时无法接受您的连接,原因可能是:

  • 请求的端口没有打开监听。

  • 监听套接字的未决连接积压已满。

无法区分是哪种情况,因此您只能在稍后重新尝试连接,最好是在经过一小段时间间隔后(例如,至少 5 秒)。如果连续多次尝试均失败,则连接失败。

如果服务器机器可访问并正在监听,但在超时期限结束之前未完成 3 次握手,您可能会收到 ETIMEDOUT 错误。

如果防火墙阻止您的连接,也可能会发生任何一个错误。

更新:根据对 an earlier answer 的评论我发帖说,如果积压已满,只有 Windows 服务器会导致 ECONNREFUSED。 *Nix 服务器导致 ETIMEDOUT 而不是。

关于android - Android 中的 Linux 套接字连接失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53735473/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com