【问题标题】:WinSock Error 10061WinSock 错误 10061
【发布时间】:2012-04-27 12:33:18
【问题描述】:

我使用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();
}

非常感谢:)

【问题讨论】:

  • 笔记本电脑上运行着什么杀毒软件?
  • 只是标准的 Windows 安全工具,尽管其中一台笔记本电脑上有 Spybot。不过我不认为这是问题所在,因为台式机上运行着 Kaspersky 或 Norton,我对这些机器没有任何问题。
  • 你能显示客户端代码吗?它如何确定要连接的 IP/端口?

标签: winsock winsock2 winsockets


【解决方案1】:

IP 端口是 16 位整数,因此允许的最大端口号为 0xFFFF (65535)。这里发生的是一种整数溢出。由于您所需的端口号 (76567) 不适合 16 位,因此该数字被截断,仅使用最低 16 位。这将为您提供端口号 11031。addr.sin_port = htons(76567); 行应该给您一个编译器警告,因为 htons() 的参数无法找到 uint16_t

【讨论】:

    【解决方案2】:

    getaddrinfo() 返回给定hints 条件的所有可用地址的链接列表。即使机器只有一个网络适配器,它也可以分配多个 IP 地址,即使是 localhost。您正在将服务器套接字绑定到getaddrinfo() 找到的第一个 IP/端口对,因此客户端可能会尝试连接到真正不在服务器上侦听的不同 IP/端口,例如,如果服务器绑定到您的 LAN/Internet IP,但客户端连接到 127.0.0.1。除非服务器绑定到127.0.0.1,否则客户端无法连接到127.0.0.1

    在多宿主/多 IP 环境中,调用bind() 时应使用通配符0.0.0.0 IP(又名INADDR_ANY),而不是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();
    }
    

    【讨论】:

    • 好主意,我试过了,但我遇到了同样的问题。在台式机上工作正常,但在 win7 笔记本电脑上不行。感谢雷米的建议:)
    • 然后使用命令行netstat工具,或者SysInternal的TCPView工具,来验证服务器是否真的在监听客户端试图连接的IP/端口,然后确保客户端实际上正在尝试连接到您认为它应该连接到的 IP/端口。
    • 快速浏览 TCPView 并显示如下: 协议:TCP 本地地址: 本地端口:11031 远程地址: 远程端口:0 状态:聆听让我感到困惑的是我将端口设置为 76567。但是本地或远程端口都没有设置为这个。再次感谢雷米。
    • 11031 是 0x2B17,76567 是 0x12B17。注意到相似之处了吗?确保正确分配端口。
    • 我认为我正确分配了端口addr.sin_port = htons(76567); 但是,我使用的是 MingGW,这可能是某种交叉编译问题,甚至是 MinGW 的 htons 功能不兼容吗?这是一个相当烦人的设置。我将 Qt + MinGW 用于服务器,将 Visual Studio 用于客户端(不是我的选择,我必须使用遗留代码:()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-28
    • 1970-01-01
    • 1970-01-01
    • 2012-11-23
    • 1970-01-01
    • 2013-03-02
    • 2018-08-09
    相关资源
    最近更新 更多