首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >连接到C++地址时拒绝IPv4 winsock连接

连接到C++地址时拒绝IPv4 winsock连接
EN

Stack Overflow用户
提问于 2013-04-21 08:01:30
回答 3查看 1.6K关注 0票数 4

我正在使用winsock2编写服务器/客户端系统的程序,当我将客户机连接到服务器名为服务器IPv6 address时,效果很好。但是,当我使用服务器IPv4 address时,在客户机中调用connect()时会出现错误“拒绝连接”。

此错误发生在我的客户端或使用telnet。但是,我可以使用三个名称( IPv4或IPv6 )中的任何一个成功地平铺服务器。

我尝试过在同一台机器上运行服务器和客户端,在不同的机器上运行,并且在所有机器上禁用防火墙。

以下是我的服务器初始化和侦听代码的摘录:

代码语言:javascript
复制
SOCKET sockfd = INVALID_SOCKET, in_socketID;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
sockaddr_storage incoming_addr;
int addr_size;
int tmp_err;
const char *sPort = "20152";

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;

tmp_err = getaddrinfo(NULL, sPort, &hints, &servinfo);
if (tmp_err != 0)
    throw exception("ERROR: getaddrinfo failed");

// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
    ip = p;
    sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if (sockfd == INVALID_SOCKET)
    {
        cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
    } // end if
    else if (bind(sockfd, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
    {
        cerr << "ERROR on bind(): " << WSAGetLastError() << endl;
        closesocket(sockfd);
        sockfd = INVALID_SOCKET;
    } // end if
} // end for

if (sockfd == INVALID_SOCKET)
{
    // looped off the end of the list with no successful bind
    throw exception("ERROR: Failed to bind socket");
}

// clean up
if (servinfo)
    freeaddrinfo(servinfo);

if (listen(sockfd, SOMAXCONN ) == SOCKET_ERROR)
    throw exception("Listen failed");

while (true)
{
    memset(&incoming_addr, 0, sizeof(incoming_addr));
    addr_size = sizeof(incoming_addr);
    in_socketID = accept(socketID, (sockaddr *)&incoming_addr, &addr_size);

    // do stuff with incoming connection
}

这是我的客户代码:

代码语言:javascript
复制
int sockfd = INVALID_SOCKET;
struct addrinfo hints;
struct addrinfo *servinfo = NULL;
struct addrinfo *p;
struct addrinfo *ip;
int tmp_err;
const char *sHost = "192.168.1.136";
const char *sPort = "20152";

memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // either IPv4 or IPv6
hints.ai_socktype = SOCK_STREAM; // use TCP

tmp_err = getaddrinfo(sHost,        // web address or ip to connect to
                      sPort,        // port or protocol
                      &hints,       // initialized hints structure
                      &servinfo);   // return structure
if (tmp_err != 0)
    throw exception("ERROR: getaddrinfo failed");

// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL && sockfd == INVALID_SOCKET; p = p->ai_next)
{
    ip = p;
    sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
    if (sockfd == INVALID_SOCKET)
    {
        cerr << "ERROR on socket(): " << WSAGetLastError() << endl;
        //continue;
    } // end if
    else if (connect(sockfd, p->ai_addr, p->ai_addrlen) < 0)
    {
        cerr << "ERROR on connect(): " << WSAGetLastError() << endl;
        closesocket(sockfd);
        sockfd = INVALID_SOCKET;
        //continue;
    } // end if
} // end for

if (sockfd == INVALID_SOCKET)
    throw exception("ERROR: Failed to connect");


// clean up
if (servinfo)
    freeaddrinfo(servinfo);

// do stuff with new socket

我已经在网站上读到了几个类似的问题,但没有人回答这个问题。

如何也连接到服务器IPv4地址?我需要帮助拜托。

谢谢。

编辑:

根据用户Sorayuki的建议,我做了一些修改,只是为了检验他的理论是否正确。

通过在服务器上进行更改,我能够连接到IPv4

代码语言:javascript
复制
hints.ai_family = AF_UNSPEC;

代码语言:javascript
复制
hints.ai_family = AF_INET;

我知道它显然会起作用,但是当我这样做的时候,IPv6当然不起作用。

看来用户Sorayuki是对的,我的循环连接到IPv6。

似乎没有一种简单的方法来统一IPv6和IPv4。您的套接字必须听其中一种或另一种,这使这个过程真的很烦人。

根据文档,同时听IPv4和IPv6的旧风格是为每个套接字创建一个套接字,并同时监听两者。这是针对Windows 2003和Windows SP1的。

最受欢迎的现代风格(Windows,7和8)是将您的套接字转换为双套接字,它将同时听IPv4和IPv6。但是,您的客户端还必须能够设置一个双套接字,因此,如果您的应用程序服务的是一个旧客户端,那么您就只能使用旧的方法。

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-21 08:13:50

是因为您将服务器套接字绑定到IPv6地址吗?在"for“循环中,出现在IPv6地址之前的IPv4地址似乎会导致服务器的套接字监听IPv6地址。因此,您的服务器没有侦听任何IPv4地址,因为所有指向服务器IPv4地址的连接都被拒绝。

尝试使用工具或命令查看所有侦听端口上的IP地址(例如。( netstat)

票数 2
EN

Stack Overflow用户

发布于 2013-04-21 20:28:56

这是因为绑定到IPv6地址也不能神奇地绑定到IPv4地址。

在Linux上,默认情况下绑定到[::]将导致IPv6和IPv4工作(除非/proc/sys/net/ipv6/bindv6only设置为1)。

然而,在Mac和Windows上,绑定到[::]只适用于IPv6。还必须绑定到IPv4地址(或0.0.0.0)才能工作。

您在注释“循环遍历所有结果并绑定到第一个我们可以”中描述的逻辑正是这里的问题所在。您应该使用[::]标志(参见setsockopt())和0.0.0.0绑定到0.0.0.0

票数 3
EN

Stack Overflow用户

发布于 2013-04-21 08:09:14

您试过在同一台计算机上运行服务器和客户端吗?

这听起来像是防火墙问题。如果您成功地在同一台机器上连接telnet /您的应用程序,您就会知道这就是问题所在。

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16129132

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档