我正在使用 winsock2 对服务器/客户端系统进行编程,当我将客户端连接到 服务器名称 或 服务器 IPv6 地址 时,它工作得很好。但是,当我使用 服务器 IPv4 地址 时,我在客户端调用 connect() 时收到错误“连接被拒绝”。
此错误发生在我的客户端或使用 telnet 时。但是,我可以使用 IPv4 或 IPv6 这三个名称中的任何一个成功地 ping 服务器。
我试过在同一台机器上运行服务器和客户端,在不同的机器上,并在所有机器上停用防火墙。
这是我的服务器初始化和监听代码的摘录:
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
}
这是我的客户端代码:
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
hints.ai_family = AF_UNSPEC;
到
hints.ai_family = AF_INET;
我知道它显然会起作用,但是当我这样做时,当然 IPv6 不起作用。
看来用户 Sorayuki 是对的,我的循环正在连接到 IPv6。
似乎没有简单的方法可以统一 IPv6 和 IPv4。您的套接字必须监听其中一个或另一个,这使得该过程非常烦人。
根据文档,同时监听 IPv4 和 IPv6 的旧样式是为每个创建一个套接字并监听两者。这适用于 Windows Server 2003 和 Windows XP SP1。
首选的现代风格(Windows Vista、7 和 8)是将您的套接字转换为双套接字,它会同时监听 IPv4 和 IPv6。但是,您的客户端还必须能够设置双套接字,因此,如果您的应用程序正在为旧客户端提供服务,您将无法使用旧方法。
谢谢!
最佳答案
是因为您将服务器套接字绑定(bind)到 IPv6 地址吗?
在“for”循环中,出现在 IPv4 地址之前的 IPv6 地址似乎导致服务器的套接字监听 IPv6 地址。
所以你的服务器没有监听任何 IPv4 地址,导致所有连接到服务器 IPv4 地址的连接都被拒绝。
尝试使用工具或某些命令(例如 netstat)查看所有监听端口位于哪个 IP 地址上
关于连接到 IPv4 地址时 C++ winsock 连接被拒绝,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16129132/