使用alarm((是唯一在Unix域套接字上设置connect((超时的方法吗?我已经尝试了这里描述的select((,但似乎select((每次都在unix域套接字上立即返回确定,并且 调用 getsockopt(SO_ERROR( 没有发生错误,但 FD 上的 send(( 返回错误说 Transport endpoint is not connected
。我粘贴下面的 select(( 代码。
我认为使用警报会满足这种情况,但似乎这是一种老式的方式。所以我在这里看看是否有任何其他解决方案。提前谢谢。
if ((flags = fcntl(fd, F_GETFL, 0)) == -1) {
syslog(LOG_USER|LOG_ERR, "fcntl get failed: %s", strerror(errno));
close(fd);
return -1;
}
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
syslog(LOG_USER|LOG_ERR, "set fd nonblocking failed: %s", strerror(errno));
close(fd);
return -1;
}
if(connect(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK && errno != EINPROGRESS) {
close(fd);
return -1;
}
FD_ZERO(&set);
FD_SET(fd, &set);
if(select(fd + 1, NULL, &set, NULL, &timeout) <= 0) {
close(fd);
return -1;
}
/*
if(connect(fd, (struct sockaddr *) &address, sizeof(struct sockaddr_un)) != 0) {
close(fd);
return -1;
}
*/
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len) < 0) {
syslog(LOG_USER|LOG_ERR, "getsockopt failed: %s", strerror(errno));
close(fd);
return -1;
}
if(error != 0) {
syslog(LOG_USER|LOG_ERR, "getsockopt return error: %d", error);
close(fd);
return -1;
}
}
if (fcntl(fd, F_SETFL, flags & ~O_NONBLOCK) == -1) {
syslog(LOG_USER|LOG_ERR, "set fd blocking failed: %s", strerror(errno));
close(fd);
return -1;
}
在另一篇文章中的某个地方(我没有为该页面添加书签(,我发现该connect()
仅建立TCP连接。这只意味着在另一端,有一个工作的TCP堆栈,但这并不意味着服务器实际上已经accept()
-ed!
connect()
的例子就像打电话给支持中心,自动语音告诉你,你在排队,但你仍然无法沟通。 accept()
是实际接听您电话的接线员。
对于同样的问题,我的解决方案是让客户端等待服务器实际发送一些东西,然后再继续处理其他客户端的东西。我可以把它放在选择超时循环中。
listen()
有一个参数,即在开始丢弃客户端连接尝试之前,可以在积压工作中放置多少个连接。
您可以在 EINPROGRESS 之后使用 select(( 或 poll((,如连接手册页中所述。 如果您获得 EAGAIN 或 EWILLBLOCK,则 Unix 域套接字已用完积压条目,即服务器通过 listen(( 调用指定的队列长度。 连接(( 失败。
请注意,连接客户端可以写入 Unix 域套接字,直到系统缓冲区已满,甚至在服务器接受调用之前。 这适用于每个积压工作缓冲区。 之后发生故障。
失败的 connect(( 可能需要一个新的套接字才能重试。 select(( 如果连接被拒绝,例如服务器没有侦听 ((,也可能返回 0。 这取决于系统和图书馆。 无论如何,在 EAGAIN 出错后,有必要重试。 例如:
int rtc, so_error, max_retry = 5;
socklen_t len = sizeof so_error;
while ((rtc = connect(fd, (struct sockaddr *)&address, sizeof address)) != 0
&& errno == EAGAIN && --max_retry >= 0) {
sleep(1);
// new socket?
}
if (rtc < 0 && errno != EINPROGRESS) {
syslog(LOG_USER|LOG_ERR, "connect returned %d: %s", rtc, strerror(errno));
close(fd);
return -1;
}
if (rtc < 0)
{
fd_set set, wset, eset;
struct timeval timeout;
timeout.tv_sec = 10;
timeout.tv_usec = 0;
FD_ZERO(&set);
FD_SET(fd, &set);
wset = set;
eset = set;
if(select(fd + 1, &set, &wset, &eset, &timeout) <= 0) {
close(fd);
return -1;
}
// [...]
}