我目前正在尝试向打开tcp连接的方法添加超时。我大致使用指南发现here除了我试图使用poll()
而不是选择。但是,我立即调用poll()
返回通知fd已准备好写入,尽管连接未打开。下面是一个减小的代码示例我公司生产:使用轮询的TCP超时
#include <cstring>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <iostream>
#include <cstdlib>
int main() {
struct addrinfo hints;
::memset(&hints, 0, sizeof(hints));
hints.ai_socktype = 0;
hints.ai_family = AF_UNSPEC;
hints.ai_protocol = 0;
hints.ai_flags = AI_CANONNAME;
struct addrinfo * info;
if(::getaddrinfo("127.0.0.1", "49999", &hints, &info) != 0) {
std::cerr << "Error: getaddrinfo" << std::endl;
exit(1);
}
int soc;
if((soc = ::socket(info->ai_family, info->ai_socktype, info->ai_protocol)) < 0) {
std::cerr << "Erorr: socket" << std::endl;
}
// Set mode to non-blocking for timeout handling
int arg;
if((arg = ::fcntl(soc, F_GETFL, 0)) < 0) {
std::cerr << "Error: fcntl" << std::endl;
exit(1);
}
arg |= O_NONBLOCK;
if(::fcntl(soc, F_SETFL, arg) < 0) {
std::cerr << "Error: fcntl" << std::endl;
exit(1);
}
int res = ::connect(soc,info->ai_addr,info->ai_addrlen);
if((res != 0) && (errno != EINPROGRESS)) {
std::cerr << "Error: connect" << std::endl;
exit(1);
}
pollfd pfd;
pfd.fd = soc;
pfd.events = POLLOUT;
res = ::poll(&pfd, 1, 50000);
if(res < 0) {
std::cerr << "Error: poll" << std::endl;
exit(1);
}
else if(res == 0) {
std::cerr << "Error: poll" << std::endl;
exit(1);
}
// Set blocking mode again
if((arg = ::fcntl(soc, F_GETFL, NULL)) < 0) {
std::cerr << "Error: fcntl" << std::endl;
exit(1);
}
arg &= (~O_NONBLOCK);
if(::fcntl(soc, F_SETFL, arg) < 0) {
std::cerr << "Error: fcntl" << std::endl;
exit(1);
}
return 0;
}
由于端口49999
是我的机器上封闭我期望的误差。程序结束后返回值为0
。
我也尝试使用上面链接中的选择示例。如果我更换呼叫poll()
与完整的例子,我得到了以下错误消息:
Operation now in progress: Operation now in progres
我试图减少使用选择的代码,但是当我降低它,我得到一个正确的connection refused message
。
编辑:
注:“正在进行操作”的消息,是由于我这边的错误处理代码中的错误。一旦我纠正了这一点,我从“getsockopt()”得到了正确的错误信息。这也解释了为什么我无法减少这个例子。
“我假设poll()会返回一个错误,如果connect()不成功”。假设你错了。 'connect()'除了阻塞之外什么都不做,直到套接字变为可写,或者超时过期。它是'connect()',如果失败则返回一个错误,并且你的代码没有正确地检查它。如果connect()返回了'EAGAIN',你现在只能通过轮询修复它;换句话说,你已经实现了我的答案。无论你是否意识到。 – EJP
是的,我注意到我错误地认为它会返回一个错误。但是'EINPROGRESS'的缺失检查并不是我困惑的问题。在我以后的测试中,代码总是到达'fprintf(stderr,“延迟连接()%d - %s \ n”错误,valopt,strerror(valopt));'所以只需添加'EINPROGRESS ''不会做任何事情,因为它使用'getsockopt()'缺少的检查(或者在另一种情况下该线路有故障)。你仍然警告过我一个潜在的未来错误,这可能会导致更多的后续调试问题。 – LiKao