零超时的非阻塞 connect() 和 select() 返回 0
non-blocking connect() and select() with zero timeout is returning 0
我正在编写一个单线程应用程序,它可以循环处理多个连接的 TCP 套接字。
这是它启动连接的部分:
// Set up connecting socket
wire[wi].skt=socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,IPPROTO_TCP);
if (wire[wi].skt==-1) return TEC_SOCK_ERR;
wire[wi].sai.sin_family=AF_INET;
memmove(&wire[wi].sai.sin_addr,&rconf.txaddr,sizeof(struct in_addr));
wire[wi].sai.sin_port=htons(rconf.txport);
// Initiate connection
int cres = connect(wire[wi].skt,(struct sockaddr *)&wire[wi].sai,sizeof(struct sockaddr_in));
// Comprehend results
if (cres==0)
{ // Connect already established
wire[wi].state=CONNECTED;
return 0;
};
if (cres==-1) // Socket error meaning depends on errno
switch (errno)
{
// This is OK for non-blocking sockets
case EINPROGRESS : { // Connect initiated
wire[wi].state=CONNECTING;
return 0;
};
default : return TEC_SOCK_ERR;
};
return 0; // Should not normally happen
显然,EINPROGRESS
是最常见的情况,因此循环中还有另一个代码
case CONNECTING : {
struct timeval tv;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(wire[wc].skt,&rfds);
memset(&tv,0,sizeof(struct timeval));
int retval = select(1,NULL,&rfds,NULL,&tv);
printf("%d:%d ",retval,errno);
fflush(stdout);
// Done
break;
};
我不明白的是为什么select
这里总是returns0和EAGAIN
,不管连接是否成功。
我正在寻找最可靠的方法来判断非阻塞套接字上的连接是否(不)成功。
提前致谢。
更新。似乎没有明显的错误,所以我会做一个 MWE 最终在其他地方找到它作为愚蠢的东西:)
您没有打电话给 select()
'regardless of whether the connection was successful or not'。您只在 EINPROGRESS 案例中调用它。如果它 returns 为零,则没有 FD 准备就绪,因此连接仍在进行中。
int retval = select(1,NULL,&rfds,NULL,&tv);
select的第一个参数不是fds的数量,而是(来自linux手册页):
nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
除非您的套接字有 fd 0(在这种情况下您必须关闭标准输入),否则您使用的值 1 是错误的。这意味着集合中所有小于 nfds(即 none)的 fds 都准备就绪,因此 select returns 0。代码应该改为:
int retval = select( 1+wire[wc].skt, NULL,&rfds,NULL,&tv);
I'm in a search for the most reliable way of telling if a connection was (not)successful on non-blocking socket.
在套接字上做一个recv
。如果已连接,recv
将 return -1,如果没有可读取的内容,您将获得 EAGAIN。如果连接不成功,recv
将 return 0.
我正在编写一个单线程应用程序,它可以循环处理多个连接的 TCP 套接字。 这是它启动连接的部分:
// Set up connecting socket
wire[wi].skt=socket(AF_INET,SOCK_STREAM | SOCK_NONBLOCK,IPPROTO_TCP);
if (wire[wi].skt==-1) return TEC_SOCK_ERR;
wire[wi].sai.sin_family=AF_INET;
memmove(&wire[wi].sai.sin_addr,&rconf.txaddr,sizeof(struct in_addr));
wire[wi].sai.sin_port=htons(rconf.txport);
// Initiate connection
int cres = connect(wire[wi].skt,(struct sockaddr *)&wire[wi].sai,sizeof(struct sockaddr_in));
// Comprehend results
if (cres==0)
{ // Connect already established
wire[wi].state=CONNECTED;
return 0;
};
if (cres==-1) // Socket error meaning depends on errno
switch (errno)
{
// This is OK for non-blocking sockets
case EINPROGRESS : { // Connect initiated
wire[wi].state=CONNECTING;
return 0;
};
default : return TEC_SOCK_ERR;
};
return 0; // Should not normally happen
显然,EINPROGRESS
是最常见的情况,因此循环中还有另一个代码
case CONNECTING : {
struct timeval tv;
fd_set rfds;
FD_ZERO(&rfds);
FD_SET(wire[wc].skt,&rfds);
memset(&tv,0,sizeof(struct timeval));
int retval = select(1,NULL,&rfds,NULL,&tv);
printf("%d:%d ",retval,errno);
fflush(stdout);
// Done
break;
};
我不明白的是为什么select
这里总是returns0和EAGAIN
,不管连接是否成功。
我正在寻找最可靠的方法来判断非阻塞套接字上的连接是否(不)成功。 提前致谢。
更新。似乎没有明显的错误,所以我会做一个 MWE 最终在其他地方找到它作为愚蠢的东西:)
您没有打电话给 select()
'regardless of whether the connection was successful or not'。您只在 EINPROGRESS 案例中调用它。如果它 returns 为零,则没有 FD 准备就绪,因此连接仍在进行中。
int retval = select(1,NULL,&rfds,NULL,&tv);
select的第一个参数不是fds的数量,而是(来自linux手册页):
nfds is the highest-numbered file descriptor in any of the three sets, plus 1.
除非您的套接字有 fd 0(在这种情况下您必须关闭标准输入),否则您使用的值 1 是错误的。这意味着集合中所有小于 nfds(即 none)的 fds 都准备就绪,因此 select returns 0。代码应该改为:
int retval = select( 1+wire[wc].skt, NULL,&rfds,NULL,&tv);
I'm in a search for the most reliable way of telling if a connection was (not)successful on non-blocking socket.
在套接字上做一个recv
。如果已连接,recv
将 return -1,如果没有可读取的内容,您将获得 EAGAIN。如果连接不成功,recv
将 return 0.