使用 getaddrinfo 连接套接字超时
Connecting a socket, using getaddrinfo, times out
我花了几个小时试图找出我的问题,只是在我写问题时找到了解决方案(当你需要正式化你的问题并解释它时,它总是有帮助的)。我post它,希望它能帮助别人。
使用 getaddrinfo,如果我尝试将一个套接字连接到我的服务器,做(我认为的)正是在大量网站以及 getaddrinfo 的手册页示例代码中所解释的,它失败了"connection timed out" 错误信息:
(精简代码更简洁)
void connect_UsingGetAddrInfo_Wrong (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
x = getaddrinfo(hostname, NULL, &hints, &addr);
//shall rather loop on addr linked list, but this is not the topic here.
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
x = connect(socketfd, addr->ai_addr, addr->ai_addrlen);
}
但是,我能够使用 gethostbyname 方法将套接字连接到同一台服务器。
void connect_UsingGetHostByName_Deprecated (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
struct hostent DNS, *r;
char buf[1024];
x = gethostbyname_r(hostname.c_str(), & DNS, buf, sizeof(buf), & r, & err));
socketfd = socket(domain, socketType, 0);
//server.
sockaddr_in server;
memset(&server, 0x00, sizeof(server));
server.sin_family=domain;
server.sin_port=htons(port);
memcpy(& server.sin_addr.s_addr, DNS.h_addr, (size_t) DNS.h_length);
x = connect(socketfd, (struct sockaddr *) & server, sizeof(server));
}
运行 代码显示两个版本都正确检索了服务器的有效 IP 地址。第一个仍然无法连接并且会超时。
为什么 ?
它一直失败的原因是:为了检索地址信息,我让字段 'service' 等于 NULL。它仍然会 return 成功并为您提供一个地址(您可以使用 getnameinfo 将其映射到正确的 IP 地址)。该地址仍然无法用于连接您的套接字!
我在这里找到了两种方法的混合版本:
https://codereview.stackexchange.com/questions/17863/socket-connect-realization-gethostbyname-or-getnameinfo
这个很实用,但我不买铸件
void connect_UsingGetAddrInfo_HYBRID (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
x = getaddrinfo(host, NULL, &hints, &addr);
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
//here is the hybrid part
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = addr->ai_family;
servAddr.sin_addr.s_addr = *((uint32_t*) & (((sockaddr_in*)addr->ai_addr)->sin_addr));
servAddr.sin_port = htons(port);
x=connect(socketfd, (struct sockaddr*) &servAddr, sizeof(servAddr));
}
最后帮我找到了根本原因:
void connect_UsingGetAddrInfo_FIXED (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
//Precise here the port !
const char* service = std::to_string(port).c_str();
x = getaddrinfo(host, service, &hints, &addr);
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
x = connect(socketfd, addr->ai_addr, addr->ai_addrlen);
}
希望有一天这会对某人有所帮助!
我花了几个小时试图找出我的问题,只是在我写问题时找到了解决方案(当你需要正式化你的问题并解释它时,它总是有帮助的)。我post它,希望它能帮助别人。
使用 getaddrinfo,如果我尝试将一个套接字连接到我的服务器,做(我认为的)正是在大量网站以及 getaddrinfo 的手册页示例代码中所解释的,它失败了"connection timed out" 错误信息: (精简代码更简洁)
void connect_UsingGetAddrInfo_Wrong (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
x = getaddrinfo(hostname, NULL, &hints, &addr);
//shall rather loop on addr linked list, but this is not the topic here.
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
x = connect(socketfd, addr->ai_addr, addr->ai_addrlen);
}
但是,我能够使用 gethostbyname 方法将套接字连接到同一台服务器。
void connect_UsingGetHostByName_Deprecated (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
struct hostent DNS, *r;
char buf[1024];
x = gethostbyname_r(hostname.c_str(), & DNS, buf, sizeof(buf), & r, & err));
socketfd = socket(domain, socketType, 0);
//server.
sockaddr_in server;
memset(&server, 0x00, sizeof(server));
server.sin_family=domain;
server.sin_port=htons(port);
memcpy(& server.sin_addr.s_addr, DNS.h_addr, (size_t) DNS.h_length);
x = connect(socketfd, (struct sockaddr *) & server, sizeof(server));
}
运行 代码显示两个版本都正确检索了服务器的有效 IP 地址。第一个仍然无法连接并且会超时。 为什么 ?
它一直失败的原因是:为了检索地址信息,我让字段 'service' 等于 NULL。它仍然会 return 成功并为您提供一个地址(您可以使用 getnameinfo 将其映射到正确的 IP 地址)。该地址仍然无法用于连接您的套接字!
我在这里找到了两种方法的混合版本: https://codereview.stackexchange.com/questions/17863/socket-connect-realization-gethostbyname-or-getnameinfo 这个很实用,但我不买铸件
void connect_UsingGetAddrInfo_HYBRID (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
x = getaddrinfo(host, NULL, &hints, &addr);
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
//here is the hybrid part
sockaddr_in servAddr;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = addr->ai_family;
servAddr.sin_addr.s_addr = *((uint32_t*) & (((sockaddr_in*)addr->ai_addr)->sin_addr));
servAddr.sin_port = htons(port);
x=connect(socketfd, (struct sockaddr*) &servAddr, sizeof(servAddr));
}
最后帮我找到了根本原因:
void connect_UsingGetAddrInfo_FIXED (std::string host, unsigned short int port, int& socketfd)
{
//simplified loops & error handling for concision
int x;
int domain = AF_INET; // IP_v4
int socketType = SOCK_STREAM; // Sequenced, reliable, connection-based byte streams.
addrinfo hints, *addr;
//fine-tune hints according to which socket you want to open
hints.ai_family = domain;
hints.ai_socktype = socketType;
hints.ai_protocol = 0; // no enum : possible value can be read in /etc/protocols
hints.ai_flags = AI_CANONNAME | AI_ALL | AI_ADDRCONFIG;
//Precise here the port !
const char* service = std::to_string(port).c_str();
x = getaddrinfo(host, service, &hints, &addr);
socketfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
x = connect(socketfd, addr->ai_addr, addr->ai_addrlen);
}
希望有一天这会对某人有所帮助!