【问题标题】:select call returning before timeout on Linux在 Linux 上选择超时前返回的调用
【发布时间】:2017-03-09 17:30:27
【问题描述】:

我开始讨厌套接字了,请帮忙。

所以我正在尝试连接到 localhost 网络中的某个位置。这可能会或可能不会在线。由于我想等待比默认值更短的超时,我使用非阻塞connect,+select

struct sockaddr_in address;
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(0x7f000001);
address.sin_port = htons(port);

const int timeout_int = 100; //in milliseconds
struct timeval timeout = { 0, timeout_int * 1000 };

SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

#ifdef WIN32
u_long iMode = 1;
ioctlsocket(s, FIONBIO, &iMode);
#else
int socketFlags = fcntl( s, F_GETFL, 0 )
socketFlags |= O_NONBLOCK;
fcntl( s, F_SETFL, socketFlags )
#endif

connect(s, (struct sockaddr*) clientService, sizeof(struct sockaddr_in));

fd_set sock;
FD_ZERO(&sock);
FD_SET(s, &sock);

int result = select(s + 1, NULL, &sock, NULL, &timeout);

当然,我遗漏了很多错误检查;但别担心,我正在做,一切看起来都很健康,只是它已经死了,可以这么说。

在 Windows 上它可以工作:它等待超时,如果没有找到,它会将 0 返回到 result,这恰好意味着“超时”。

然而,在完全相同的情况下,Linux 几乎立即返回 1 - 这意味着套接字已准备好写入!确实,套接字标志仍然设置。

现在,有人建议我这样做

int soError;
socklen_t len = sizeof(soError);
getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&soError, &len);

那么只有soError0,连接成功。

但是为什么没有等待超时呢?我可以相信 Linux 知道,如果我到了那个地步,就已经没有希望得到答案了吗? 我已经尝试在剩余的超时时间内睡觉,然后再次检查;但在那种情况下,我在所有情况下都会得到soError == 0,所以它不起作用。

或者我在其他时候做错了什么?

【问题讨论】:

  • clientService 是什么? BTW 100 uSec 非常短。为什么不让它 5 秒左右?
  • 由于select() 只是检查写入套接字是否会阻塞,如果您尝试写入套接字会发生什么?
  • 这个问题似乎令人困惑。您是在尝试读取还是写入您的套接字?如果您尝试阅读,则应使用以下顺序:调用 connect,如果它返回 -1 并且 errno == EINPROGRESS,然后像您一样调用 select(检查套接字是否写入),当 select 返回 1 时检查 SO_ERROR 是否有可能的错误。如果没有错误,您已连接。现在您可以读取或写入套接字。如果要等待输入,请使用另一个选择(现在检查套接字以进行读取)。如果它返回 1,则会收到一条消息并且可以阅读。我错过了什么吗?
  • 如果select 返回套接字是可写的,那么您已连接并且服务器正在侦听。您可以write 到套接字。在您的情况下,select 在超时之前返回,因为连接的建立速度比超时 100 毫秒快。问题是什么?您是否尝试过简单地向套接字写入一些内容?究竟是什么不起作用?
  • 您拥有的是non blocking connect,行为完全正常。 GIYF BTW:如果 select 说 fd 是可写的:这意味着您可以在不阻塞的情况下对其进行写入。写入可以返回 0 或 -1,但不会阻塞。

标签: c linux sockets


【解决方案1】:

并非所有连接错误都需要超时。例如,ECONNREFUSED 会导致立即失败。超时用于对等方根本没有响应的情况。

【讨论】:

  • 你的意思是select 收到了一些叫做ECONNREFUSED 的东西?因为 it 返回给 me 的东西看起来像成功一样的所有意图和目的;除非我至少检查getsockopt
【解决方案2】:

您应该检查连接返回代码,只有当它返回 ERROR 并且 errno 是 EWOULDBLOCK 或 EINPROGRESS(取决于操作系统)时,才调用 select。可能是在连接调用上建立了连接,因此对 select 的调用返回您已经可以写入该套接字

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-15
    • 2019-06-22
    • 2019-09-25
    • 1970-01-01
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多