下面的代码用于套接字连接到运行在Ubuntu15.10上的服务器:
void Connect(std::string address, int port)
{
struct addrinfo hints;
struct addrinfo *result = NULL;
struct addrinfo *rp = NULL;
int sfd, s;
std::cout << "Connecting to address " << address << " port " << port << std::endl;
std::memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPV4 or IPV6 */
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
std::string portStr;
portStr = std::to_string(port);
s = getaddrinfo(address.c_str(), portStr.c_str(), &hints, &result);
std::cout << "ADDRESS-------------> " << s << std::endl;
if (s != 0)
{
std::stringstream ss;
ss << "Cannot resolve hostname " << address << gai_strerror(s);
throw std::runtime_error(ss.str());
}
/*
* getaddrinfo() returns a list of address structures. We should try each
* address until we successfull bind. If socket() or connect() fails, we close the socket
* and try the next address until the end.
*/
for (rp = result; rp != NULL; rp = rp->ai_next)
{
std::cout << "loop-----------------> " << rp->ai_family << std::endl;
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
std::cout << "sfd-----------------> " << sfd << std::endl;
if (sfd == -1)
continue;
/*
* If connect succeed, the address was found.
*/
int sts = connect(sfd, rp->ai_addr, rp->ai_addrlen);
std::cout << "sts-----------------> " << sts << std::endl;
if (sts == 0)
break;
close(sfd);
}
/*
* Check for failure
*/
if (rp == NULL)
{
std::stringstream ss;
ss << "Cannot find server address at " << address << " port " << port;
throw std::runtime_error(ss.str());
}
freeaddrinfo(result); /* Object no longer needed */
std::cout << "SOCKET-----------------> " << sfd << std::endl;
currentSocket = sfd;
}我的问题是,这段代码正在连接套接字,即使IP地址不可用。检查结果:
以下是运行时输出:
Connecting to address 192.168.0.185 port 9090
ADDRESS-------------> 0
loop-----------------> 2
sfd-----------------> 5
sts-----------------> 0
SOCKET-----------------> 5
$ ping 192.168.0.185
PING 192.168.0.185 (192.168.0.185) 56(84) bytes of data.
From 192.168.0.185 icmp_seq=1 Destination Host Unreachable
From 192.168.0.185 icmp_seq=2 Destination Host Unreachable
From 192.168.0.185 icmp_seq=3 Destination Host Unreachable我想了解这是怎么回事?为什么它将套接字从一个不存在的Ip地址连接到一个端口?
发布于 2016-04-12 22:26:11
您正在将一个IPv4地址而不是主机名传递给getaddrinfo() (不过,您应该在hints.ai_flags字段中指定AI_NUMERICHOST )。它将输出一个包含该IP地址的sockaddr_in的单个sockaddr_in,因为它不会试图验证IP的存在。这就是为什么getaddrinfo()返回0。
您告诉getaddrinfo(),您将使用的是UDP (SOCK_DGRAM)套接字,而不是TCP (SOCK_STREAM)套接字。因此,输出addrinfo包含在调用socket()时创建UDP套接字的信息。
然后在UDP套接字上调用connect()。在UDP中,connect()实际上并不像对TCP那样创建物理连接。它只是将指定的对等IP分配给套接字,这样就可以使用send()和recv()来代替sendto()和recvfrom()。这就是为什么connect()返回0而不是失败的原因。这样做允许send()始终将数据包发送到同一个IP,而recv()只接收来自同一个IP的数据包。
您还没有实际发送任何数据,因此在代码的任何一步都不会验证对等IP。一旦开始发送数据,传输的数据包最终将从网络接收ICMP主机无法访问的错误,从而导致send()和recv()开始失败。
因此,如果希望connect()对不可访问的IP地址失败,请创建一个TCP套接字而不是UDP套接字。否则,如果您继续使用UDP套接字,则需要将数据发送到IP,以便网络将其物理路由。
顺便说一下,如果connect()确实失败了,那么只有在freeaddrinfo()成功的情况下,您才会泄漏输出addrinfo,因为您正在调用freeaddrinfo()。无论您如何使用freeaddrinfo()数据,只要getaddrinfo()成功,您都需要调用addrinfo。
发布于 2016-04-12 22:37:07
UDP 'connect‘不是网络操作。它在本地API中设置了一个允许,它过滤掉来自其他主机的数据报,并允许您使用send()而不是sendto()。它不会失败,但随后会发送遗嘱。
https://stackoverflow.com/questions/36584995
复制相似问题