我目前正在嘗試向打開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