如何使用Winsock API控制连接超时

How to control the connect timeout with the Winsock API?

本文关键字:连接 超时 控制 API 何使用 Winsock      更新时间:2023-10-16

我正在使用Winsock API编写程序,因为一个朋友想要一个简单的程序来检查并查看Minecraft服务器是否正在运行。如果它正在运行,它可以正常工作,但是如果它没有运行,程序会冻结,直到我假设连接超时。另一个问题是,如果我有这样的东西(伪代码):

void connectButtonClicked()
{
     setLabel1Text("Connecting");
     attemptConnection();
     setLabel1Text("Done Connecting!");
}

似乎直接跳转到attemptConnection(),完全忽略了上面的内容。我注意到这一点是因为程序会冻结,但它不会将标签更改为"正在连接"。

下面是我实际的连接代码:

bool CConnectionManager::ConnectToIp(String^ ipaddr)
{
    if(!m_bValid)
        return false;
    const char* ip = StringToPConstChar(ipaddr);
    m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(isalpha(ip[0]))
    {
        ip = getIPFromAddress(ipaddr);
    }
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_addr.s_addr = inet_addr(ip);
    service.sin_port = htons(MINECRAFT_PORT);
    if(m_socket == NULL)
    {
        return false;
    }
    if (connect(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
    {
        closesocket(m_socket);
        return false;
    }
    else
    {
        closesocket(m_socket);
        return true;
    }
    return true;
}

在CConnectionManager的构造函数中也有代码来启动Winsock API等。

那么,我如何避免这种冻结,并允许我在连接期间更新进度条之类的东西?我必须在一个单独的线程中进行连接吗?我只在Java中使用线程,所以我不知道如何做到这一点:/

也:我正在使用一个CLR Windows窗体应用程序
我使用的是Microsoft Visual c++ 2008 Express Edition

您的代码没有跳过标签更新。更新仅仅涉及发出尚未处理的窗口消息,这就是为什么在连接套接字之前没有看到新文本出现的原因。在连接套接字之前,您必须抽取消息队列中的新消息。

至于套接字本身,不幸的是,WinSock API中没有连接超时。要实现手动超时,有两种选择:

1)假设你正在使用阻塞套接字(套接字默认是阻塞的),在一个单独的工作线程中执行连接。

2)如果您不想使用线程,那么将套接字切换到非阻塞模式。连接套接字将始终立即退出,因此您的主代码不会被阻塞,然后您将收到连接是否成功的通知。有几种方法可以检测,这取决于您使用的API - WSAAsyncSelect(), WSAAsyncEvent()或select()。

无论哪种方式,当连接正在进行时,在主线程中运行计时器。如果连接成功,停止定时器。如果计时器超时,断开套接字,这将导致连接中止并出现错误。

也许你想在这里阅读:

为了确保在连接的套接字关闭之前所有数据都在其上发送和接收,应用程序应该在调用closesocket之前使用shutdown来关闭连接。http://msdn.microsoft.com/en-us/library/ms740481%28v=VS.85%29.aspx

由于您处于阻塞模式,仍然可能有一些数据…