我使用winsock编写了一个简单的客户端/服务器应用程序。服务器和客户端通过本地主机上的TCP端口76567(只是我选择的随机数)进行连接和通信。我在三台台式机上测试了它,两台运行XP,另一台运行Win7,我也在四台笔记本电脑上测试过,三台运行Win7,一台运行XP。该应用程序适用于所有桌面计算机和XP笔记本电脑,但在所有三台Win7笔记本电脑上,当客户端尝试连接到服务器时,我得到错误10061!
我关闭了防火墙,但问题仍然存在,我也环顾四周看看导致此错误的原因,看起来客户端正在尝试连接到非侦听服务器。但是,服务器调用listen()成功返回!很奇怪这个问题似乎只发生在Win7笔记本电脑上,任何想法?
这是我的套接字初始化代码:
// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
}
// Create a server socket
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
iResult = getaddrinfo(NULL, DEFAULT_PORT, &hints, &result);
if(iResult != 0)
{
printf("getaddrinfo failed: %d\n", iResult);
WSACleanup();
}
// Create a socket to listen for clients
listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %d\n", WSAGetLastError());
freeaddrinfo(result);
WSACleanup();
}
// Bind socket to ip address and port
iResult = bind(listenSocket, result->ai_addr, (int) result->ai_addrlen);
if(iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(listenSocket);
WSACleanup();
}
freeaddrinfo(result);
// Listen for connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
printf("Listen failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}
非常感谢:)
答案 0 :(得分:2)
IP端口是16位整数,因此允许的最大端口号为0xFFFF(65535)。这里发生的是整数溢出。由于您所需的端口号(76567)不适合16位,因此该数字将被截断,并且仅使用最低16位。这为您提供了端口号11031.行addr.sin_port = htons(76567);
应该给您一个编译器警告,因为htons()
的参数无法进入uint16_t
。
答案 1 :(得分:0)
getaddrinfo()
返回给定hints
条件的所有可用地址的链接列表。即使机器只有一个网络适配器,它也可以分配多个IP地址,即使是localhost也是如此。您正在将服务器套接字绑定到getaddrinfo()
找到的第一个IP /端口对,因此客户端可能正在尝试连接到真正未在服务器上侦听的其他IP /端口,例如如果服务器绑定到您的LAN / Internet IP但客户端正在连接到127.0.0.1
。除非服务器绑定到127.0.0.1
,否则客户端无法连接到127.0.0.1
。
在多宿主/多IP环境中,您应该在调用0.0.0.0
而不是INADDR_ANY
时使用通配符bind()
IP(又名result->ai_addr
)。这会将套接字绑定到所有已安装的网络适配器的所有可用IP。这样,客户端可以连接到服务器绑定的任何IP,包括127.0.0.1
。事实上,根据您展示的代码,您根本不需要使用getaddrinfo()
:
// Initialise Winsock
iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
if(iResult != 0)
{
printf("WSAStartup failed: %d\n", iResult);
}
// Create an IPv4 server socket to listen for IPv4 clients
listenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if(listenSocket == INVALID_SOCKET)
{
printf("Error at socket(): %d\n", WSAGetLastError());
WSACleanup();
}
// Bind socket to IPv4 address and port
sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(76567);
addr.sin_addr.s_addr = INADDR_ANY;
iResult = bind(listenSocket, (sockaddr*)&addr, sizeof(addr));
if(iResult == SOCKET_ERROR)
{
printf("bind failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}
// Listen for IPv4 connection requests
if(listen(listenSocket, SOMAXCONN) != 0)
{
printf("Listen failed with error: %d\n", WSAGetLastError());
closesocket(listenSocket);
WSACleanup();
}