您的代码有多个问题:
-
首先,您正确地调用了
getaddrinfo()
,但随后您完全丢弃了结果而不使用它们。
-
你打过电话
listen()
但您似乎打算进行传出连接;
列表()
用于侦听传入连接。
-
而不是使用来自
获取地址信息()
在填写您的
sockaddr_in
结构这部分代码应该被废弃。
-
无需显式检查返回的地址族。你不会得到任何计算机无法处理的地址族。
-
您似乎正在编写一个方法,它可以做多件事,即既可以进行传出连接,也可以接受传入连接。方法只能做一件事。
让我们回到开头,建立一个最小的传出连接。这里我省略了与创建连接无关的任何内容(例如
WSAAsyncSelect()
以及其他属于单独方法的东西):
// Connect to a remote host, given its address and port number.
bool Connect(short port, std::string addr)
{
struct addrinfo *result, *rp;
// TODO: You passed us an integer port number. We need a C string.
// Clean up this mess.
char portstr[255];
portstr = sprintf("%d", port);
if (getaddrinfo(addr.c_str(), portstr, nullptr, &result)) {
throw runtime_error("getaddrinfo: " + WSAGetLastError());
}
// A host can have multiple addresses. Try each of them in turn until
// one succeeds. Typically this will try the IPv6 address first, if
// one exists, then the IPv4 address. The OS controls this ordering
// and you should not attempt to alter it. (RFC 6724)
for (rp = result; rp != nullptr; rp = rp->ai_next) {
this->hSocket = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
// Check socket creation failed; maybe harmless (e.g. computer
// doesn't have IPv6 connectivity). Real errors will get thrown below.
if (this->hSocket == -1)
continue;
if (connect(this->hSocket, rp->ai_addr, rp->ai_addrlen) != -1)
break; // Success
close(this->hSocket);
}
if (rp == NULL) { // No address succeeded
throw runtime_error("connect: " + WSAGetLastError());
}
freeaddrinfo(result);
// Now this->hSocket has an open socket connection. Enjoy!
}
主要需要注意的是
获取地址信息()
为您处理所有的重物。它返回的结构具有创建连接所需的所有信息;你只需要使用它。
如果您需要连接信息,例如地址和家庭,可以将这些信息复制到
rp
并在其超出范围之前将其存储在某处。
编写单独的方法来处理传入连接是留给读者的练习。示例代码似乎部分基于
the MSDN page for getaddrinfo
; 这个
Linux
getaddrinfo
manual page
有更好的示例(示例代码实际上在Windows上只做了很少的更改)。