当前位置: 首页 > 知识库问答 >
问题:

是否易于连接到IPv6或IPv4?

子车俊哲
2023-03-14

我正在创建套接字类,但我想使我的连接功能是动态的,可以连接到地址(ipv4或ipv6),使用交换机进行IPv测试并连接到支持的IPv,只是想问一下我是否是对的,或者有没有一个简单的方法使它成为ipv4或ipv6?

bool Connect(short port,std::string addr,bool vlisten,HWND WindowHandle,WSADATA& wsaData,bool async)
    {
        if(!hSocket);
        {
            this->port = port;
            this->addr =addr;
            this->vlisten = vlisten;
            this->WindowHandle = WindowHandle;
            this->wsaData =wsaData;
            this->init = true;

            // Provide big enough buffer, ipv6 should be the biggest
            char ipstr[INET6_ADDRSTRLEN];
            char ipstr2[INET6_ADDRSTRLEN];

            struct sockaddr_in* sockaddr_ipv4;
            struct sockaddr_in6* sockaddr_ipv6;
            //struct sockaddr_in6* sockaddr_ipv6;
            if(WSAStartup(MAKEWORD(2,2),&wsaData) !=0)
            {
                throw runtime_error("Error WSAStartup:" + WSAGetLastError());
            }

            if((this->hSocket = ::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))== INVALID_SOCKET)
            {
                Close();
                throw runtime_error("Error init sockect:" + WSAGetLastError());
            }

            if(addr != "INADDR_ANY")
            {
                struct addrinfo *result = nullptr;
                getaddrinfo(addr.c_str(), nullptr, nullptr, &result);
                struct addrinfo *it;
                for (it = result; it != nullptr; it = it->ai_next)
                {
                    //sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
                    //addr = inet_ntoa(sockaddr_ipv4->sin_addr);
                    //if (addr != "0.0.0.0") break;
                    switch (it->ai_family) 
                    {
                    case AF_UNSPEC:
                        cout<<"Unspecified\n"<<endl;
                        break;
                    case AF_INET:
                        cout<<"AF_INET (IPv4)\n"<<endl;
                        sockaddr_ipv4 = reinterpret_cast<sockaddr_in*>(it->ai_addr);
                        //printf("\tIPv4 address %s\n",
                        addr = inet_ntoa(sockaddr_ipv4->sin_addr);
                        /*if (addr != "0.0.0.0") break;*/
                        break;
                    case AF_INET6:
                        cout<<"AF_INET (IPv6)\n"<<endl;
                        sockaddr_ipv6 = reinterpret_cast<sockaddr_in6*>(it->ai_addr);
                        addr = inet_ntop(it->ai_family,sockaddr_ipv6,(PSTR)ipstr,sizeof(ipstr));
                        break;
                    case AF_NETBIOS:
                        cout<<"AF_NETBIOS (NetBIOS)\n"<<endl;
                        break;
                    default:
                        printf("Other %ld\n", it->ai_family);
                        break;

                    }
                }
                freeaddrinfo(result);
            }
        }
        SOCKADDR_IN sockAddrIn;
        memset(&sockAddrIn,0,sizeof(sockAddrIn));
        sockAddrIn.sin_port = htons(port);
        sockAddrIn.sin_family =  AF_INET;
        sockAddrIn.sin_addr.s_addr = (addr == "INADDR_ANY" ? htonl(INADDR_ANY) : inet_addr(addr.c_str()));

        if(vlisten && (bind(hSocket,reinterpret_cast<SOCKADDR*>(&sockAddrIn),sizeof(sockAddrIn))== SOCKET_ERROR))
        {
            Close();
            throw runtime_error("Error vlisten & bind: " + WSAGetLastError());
        }

        if(async && WindowHandle)
        {
            if(WSAAsyncSelect(hSocket,WindowHandle,WM_SOCKET,FD_READ|FD_WRITE|FD_CONNECT|FD_CLOSE|FD_ACCEPT) !=0)
            {
                Close();
                throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
            }

        }

        if(vlisten && (listen(hSocket,SOMAXCONN)== SOCKET_ERROR))
        {
            Close();
            throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
        }

        if(!vlisten && (connect(hSocket, reinterpret_cast<SOCKADDR*>(&sockAddrIn), sizeof(sockAddrIn)) == SOCKET_ERROR))
        {
            if(async && WindowHandle && (WSAGetLastError() != WSAEWOULDBLOCK))
            {
                Close();
                throw runtime_error("Error async & WindowHandle: " + WSAGetLastError());
            }
        }
    }

共有1个答案

丁德义
2023-03-14

您的代码有多个问题:

  • 首先,您正确地调用了getAddrInfo(),但随后您完全丢弃了结果而不使用它们。
  • 您调用了listen()但似乎打算建立传出连接;listen()用于侦听传入的连接。
  • 在填写sockaddr_in结构时,您不使用getaddrinfo()中的信息,而是忽略它并假定为IPv4。这部分代码应立即报废。
  • 不需要显式检查返回的地址族。您将不会得到任何计算机无法处理的地址族。
  • 您似乎正在编写一个完成多项任务的方法,即建立传出连接和接受传入连接。方法应该只做一件事。

让我们回到开头,得到一个最小的传出连接。我在这里省略了与创建连接没有直接关系的内容(例如,调用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!
}
 类似资料:
  • 问题内容: 是 InetAddress.getHostAddress()的IPv6兼容的JDK 1.6? 我具体在做 是否符合ipv6?它对ipv4和v6地址都有效吗? 问题答案: 我查看了InetAddress类的代码,它确实在做正确的事情。

  • 我的connect调用的结果始终是10061:连接被拒绝。 如果我将服务器代码更改为绑定到::(或者将空主机传递给getaddrinfo()(同样的事情)),并将客户机代码更改为在getaddrinfo()调用中指定空主机,那么V4客户机可以很好地连接。 谁能解释一下为什么?我没有读到任何东西,如果我们想要双套接字行为,我们必须指定一个空主机(因此使用INADDR_ANY)。这不可能是一个要求,因

  • 但是它太复杂了,无法从Java代码中完成,我认为这不是我应该使用的方向。 提前谢了。

  • 问题内容: 我写了一个函数来为一个简单的博客引擎创建帖子: 当多个用户同时删除标签并创建帖子时,是否容易出现竞争状况? 具体来说,交易(以及功能)是否可以防止此类竞争情况的发生? 我正在使用PostgreSQL 9.2.3。 问题答案: 它的经常性问题 _ 或下可能并发写入负载,涉及(但不同于)(这是 或_)。 对于Postgres 9.5或更高版本 使用新的UPSERT实施,我们可以大大简化。P

  • 代码如下 有人能帮忙吗,是不是在我可以把信息上传到表中之前就关闭连接了?

  • 我有通过核心蓝牙框架连接BLE设备和通过外部附件框架连接经典蓝牙设备的应用程序(活动的和正在维护中的)。 启用/实施核心定位框架是否有助于更好地与BLE或经典蓝牙设备连接。