【发布时间】:2021-01-27 00:24:17
【问题描述】:
我已经设置了一个可以工作的 WinSock2 Socket,如果客户端可以连接,我如何获取已连接客户端的 IP 地址。
【问题讨论】:
标签: c++ server ip-address winsock2
我已经设置了一个可以工作的 WinSock2 Socket,如果客户端可以连接,我如何获取已连接客户端的 IP 地址。
【问题讨论】:
标签: c++ server ip-address winsock2
第一次接受客户端时,accept() 会报告客户端的 IP 地址。也可以随时使用getpeername()从客户端SOCKET查询。这两个函数都根据您使用socket() 创建服务器套接字时分配的地址类型填充您必须分配和传递的sockaddr_... 结构:
AF_INET,提供sockaddr_in 结构:sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET client = accept(server, (sockaddr*)&client_addr, &clientAddrSize);
if (client != INVALID_SOCKET)
{
// use client_addr.sin_addr as needed...
...
clientAddrSize = sizeof(clientAddr);
if (getpeername(client, (sockaddr*)&client_addr, &clientAddrSize) == 0)
{
// use client_addr.sin_addr as needed...
}
...
closesocket(client);
}
AF_INET6 启用IPV6_V6ONLY,则提供sockaddr_in6 结构:sockaddr_in6 clientAddr;
int clientAddrSize = sizeof(clientAddr);
SOCKET client = accept(server, (sockaddr*)&client_addr, &clientAddrSize);
if (client != INVALID_SOCKET)
{
// use client_addr.sin6_addr as needed...
...
clientAddrSize = sizeof(clientAddr);
if (getpeername(client, (sockaddr*)&client_addr, &clientAddrSize) == 0)
{
// use client_addr.sin6_addr as needed...
}
...
closesocket(client);
}
AF_INET6 禁用IPV6_V6ONLY,则提供sockaddr_storage 结构,然后查看其ss_family 字段以了解是否将sockaddr_storage 数据转换为sockaddr_in 或sockaddr_in6:李>
sockaddr_storage clientAddr;
sockaddr_in *clientAddr4;
sockaddr_in6 *clientAddr6;
int clientAddrSize = sizeof(clientAddr);
SOCKET client = accept(server, (sockaddr*)&client_addr, &clientAddrSize);
if (client != INVALID_SOCKET)
{
switch (client_addr.ss_family)
{
case AF_INET:
clientAddr4 = use reinterpret_cast<sockaddr_in*>(&client_addr);
// use clientAddr4->sin_addr as needed...
break;
case AF_INET6:
clientAddr6 = use reinterpret_cast<sockaddr_in6*>(&client_addr);
// use clientAddr6->sin6_addr as needed...
break;
}
...
clientAddrSize = sizeof(clientAddr);
if (getpeername(client, (sockaddr*)&client_addr, &clientAddrSize) == 0)
{
switch (client_addr.ss_family)
{
case AF_INET:
clientAddr4 = use reinterpret_cast<sockaddr_in*>(&client_addr);
// use clientAddr4->sin_addr as needed...
break;
case AF_INET6:
clientAddr6 = use reinterpret_cast<sockaddr_in6*>(&client_addr);
// use clientAddr6->sin6_addr as needed...
break;
}
}
...
closesocket(client);
}
【讨论】:
sockaddr_... 的唯一函数是getaddrinfo(),但是用于主机名查找,而不是套接字查询。