winsock2:服务器端代码调用accept()后,如何获取已连接客户端的ipv4/ipv6地址



这个网站上还有其他类似的问题,但它们要么与winsock2无关,要么只适合与ipv4地址空间一起使用。Visual Studio 2019的默认编译器在使用ntoa函数时会产生错误,因此需要ipv4和ipv6解决方案。

我曾经为Linux系统编写过这样的代码,但是我目前在工作,没有访问权限。可以使用winsock2将它"复制粘贴"到windows环境中,也可以不使用。(编辑:我当然会在今晚晚些时候添加代码,但当然它可能没有用。)

下面包含一个示例,但是这是一个客户端代码的示例,而不是服务器端代码。https://www.winsocketdotnetworkprogramming.com/winsock2programming/winsock2advancedInternet3c.html

在这里,getaddrinfo()函数用于获得包含匹配的ipv4和ipv6地址的结构。要获得此信息,需要与DNS进行一些交互,在本例中不需要。

我有一些服务器代码调用accept()(绑定和监听后)接受客户端连接。我希望能够打印客户端ip地址和端口到stdout。

这个网站上最相关的问题在这里。然而,答案使用ntoa,并且只兼容ipv4。

目前为止我有什么:

到目前为止,我已经画出了这样的草图:

SOCKET acceptSocket = INVALID_SOCKET;
SOCKADDR_IN addr; // both of these are NOT like standard unix sockets
// I don't know how they differ and if they can be used with standard
// unix like function calls (eg: inet_ntop)
int addrlen = sizeof addr;
acceptSocket = accept(listenSocket, (SOCKADDR*)&addr, &addrlen);
if(acceptSocket == INVALID_SOCKET)
{
// some stuff
}
else
{
const std::size_t addrbuflen = INET6_ADDRSRTLEN;
char addrbuf[addrbuflen] = ''
inet_ntop(AF_INET, (void*)addr.sin_addr, (PSTR)addrbuf, addrbuflen);
// above line does not compile and mixes unix style function calls
// with winsock2 structures
std::cout << addrbuf << ':' << addr.sin_port << std::endl;
}

getpeername ()

int ret = getpeername(acceptSocket, addrbuf, &addrbuflen);
// addrbuf cannot convert from char[65] to sockaddr*
if(ret == ???)
{
// TODO
}

您需要访问SOCKADDR。这实际上是一个受歧视的工会。第一个字段告诉您它是IPv4 (==AF_INET)还是IPv6 (==AF_INET6)地址。根据具体情况,您可以将addr指针强制转换为struct sockaddr_in*struct sockaddr_in6*,然后从相关字段读取IP地址。

vs2019中的c++代码片段:

char* CPortListener::get_ip_str(struct sockaddr* sa, char* s, size_t maxlen)
{
switch (sa->sa_family) {
case AF_INET:
inet_ntop(AF_INET, &(((struct sockaddr_in*)sa)->sin_addr),
s, maxlen);
break;

case AF_INET6:
inet_ntop(AF_INET6, &(((struct sockaddr_in6*)sa)->sin6_addr),
s, maxlen);
break;

default:
strncpy(s, "Unknown AF", maxlen);
return NULL;
}

return s;
}
Example:


{
...

char s[INET6_ADDRSTRLEN];
sockaddr_storage ca;
socklen_t al = sizeof(ca);
SOCKET recv = accept(sd, (sockaddr*)&ca, &al);
pObj->m_ip = get_ip_str(((sockaddr*)&ca),s,sizeof(s));
}

最新更新