【发布时间】: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);
那么只有soError是0,连接成功。
但是为什么没有等待超时呢?我可以相信 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,但不会阻塞。