使用alarm()是唯一在unix域套接字上设置connect()超时的吗?我已经尝试过select(),它被描述为here,但似乎select()每次都会在unix域套接字上立即返回ok
调用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;
}
答案 0 :(得分:0)
在另一个帖子中的某个地方(我没有为该页面添加书签),我发现connect()
仅建立了TCP连接。这仅意味着在另一端,有一个有效的TCP堆栈,但这并不意味着服务器实际上已经进行了accept()
-ed!
例如connect()
的示例就像呼叫支持中心,自动语音告诉您,您正在排队,但仍然无法交流。 accept()
是接听电话的实际话务员。
对于相同问题,我的解决方案是让客户端在继续其他客户端程序之前,等待服务器实际发送一些内容。我可以将其放入选择超时循环中。
listen()
有一个参数,可以在开始删除客户端连接尝试之前将多少个连接放入待办事项中。
答案 1 :(得分:0)
您可以在EINPROGRESS之后使用select()或poll(),如connect man page中所述。如果得到EAGAIN或EWOULDBLOCK,则Unix域套接字已用完积压条目,即由服务器通过listen()调用指定的队列长度。 connect()失败。
请注意,在服务器甚至没有接受调用之前,连接的客户端都可以写入Unix域套接字,直到系统缓冲区已满为止。这适用于每个积压缓冲区。之后会发生故障。
失败的connect()在重试之前可能需要新的套接字。如果连接被拒绝(例如服务器未监听),则select()可能也会返回0。这取决于系统和libray。无论如何,在发生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;
}
// [...]
}