【问题标题】:c++ Windows 10 Get an Ip for a connected clientc++ Windows 10 获取已连接客户端的 Ip
【发布时间】:2021-01-27 00:24:17
【问题描述】:

我已经设置了一个可以工作的 WinSock2 Socket,如果客户端可以连接,我如何获取已连接客户端的 IP 地址。

【问题讨论】:

    标签: c++ server ip-address winsock2


    【解决方案1】:

    第一次接受客户端时,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_in?
    • @ColinSutter 不,您必须预先分配它并将其传递给要填充的套接字。为您分配sockaddr_... 的唯一函数是getaddrinfo(),但是用于主机名查找,而不是套接字查询。
    猜你喜欢
    • 2019-06-20
    • 2011-06-12
    • 2016-07-30
    • 2021-06-01
    • 2013-05-18
    • 2018-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多