简体   繁体   English

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

[英]How to control the connect timeout with the Winsock API?

I'm writing a program using the Winsock API because a friend wanted a simple program to check and see if a Minecraft server was running or not. 我正在使用Winsock API编写程序,因为一个朋友想要一个简单的程序来检查Minecraft服务器是否正在运行。 It works fine if it is running, however if it is not running, the program freezes until, I'm assuming, the connection times out. 如果它正在运行,它可以正常工作,但是,如果它不在运行,则程序将冻结直到我假设连接超时。 Another issue is, if I have something like this (pseudo-code): 另一个问题是,如果我有类似以下内容(伪代码):

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

it seems to skip right to attemptConnection(), completely ignoring whats above it. 它似乎跳过了tryConnection()的权限,完全忽略了它上面的内容。 I notice this because the program will freeze, but it wont change the label to "Connecting". 我注意到这是因为程序将冻结,但不会将标签更改为“正在连接”。

Here is my actual connection code: 这是我的实际连接代码:

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;
}

There is also code in the CConnectionManager's contructor to start up Winsock API and such. CConnectionManager的构造器中也有代码可以启动Winsock API等。

So, how do I avoid this freeze, and allow me to update something like a progress bar during connection? 因此,如何避免这种冻结,并允许我在连接期间更新进度条之类的内容? Do I have to make the connection in a separate thread? 我是否必须在单独的线程中进行连接? I have only worked with threads in Java, so I have no idea how to do that :/ 我只使用Java中的线程,所以我不知道该怎么做:/

Also: I am using a CLR Windows Form Application 另外:我正在使用CLR Windows窗体应用程序
I am using Microsoft Visual C++ 2008 Express Edition 我正在使用Microsoft Visual C ++ 2008 Express Edition

Your code does not skip the label update. 您的代码不会跳过标签更新。 The update simply involves issuing window messages that have not been processed yet, that is why you do not see the new text appear before connecting the socket. 该更新仅涉及发出尚未处理的窗口消息,这就是为什么在连接套接字之前看不到新文本出现的原因。 You will have to pump the message queue for new messages before connecting the socket. 在连接套接字之前,您将必须为新消息泵送消息队列。

As for the socket itself, there is no connect timeout in the WinSock API, unfortunately. 至于套接字本身,不幸的是,WinSock API中没有连接超时。 You have two choices to implement a manual timeout: 您有两种选择来实现手动超时:

1) Assuming you are using a blocking socket (sockets are blocking by default), perform the connect in a separate worker thread. 1)假设您正在使用阻塞套接字(默认情况下套接字处于阻塞状态),请在单独的工作线程中执行连接。

2) If you don't want to use a thread then switch the socket to non-blocking mode. 2)如果您不想使用线程,则将套接字切换为非阻塞模式。 Connecting the socket will always exit immediately, so your main code will not be blocked, then you will receive a notification later on if the connection was successful or not. 连接套接字总是会立即退出,因此您的主代码不会被阻止,然后您会在以后收到连接成功的通知。 There are several ways to detect that, depending on which API you use - WSAAsyncSelect(), WSAAsyncEvent(), or select(). 有几种方法可以检测到这种情况,具体取决于您使用的API-WSAAsyncSelect(),WSAAsyncEvent()或select()。

Either way, while the connect is in progress, run a timer in your main thread. 无论哪种方式,在进行连接时,都要在主线程中运行一个计时器。 If the connect succeeds, stop the timer. 如果连接成功,请停止计时器。 If the timer elapses, disconnect the socket, which will cause the connect to abort with an error. 如果计时器过去,请断开套接字,这将导致连接异常中止。

Maybe you want to read here: 也许您想在这里阅读:

To assure that all data is sent and received on a connected socket before it is closed, an application should use shutdown to close connection before calling closesocket. 为了确保所有数据在关闭之前在连接的套接字上发送和接收,应用程序应在调用closesocket之前使用shutdown关闭连接。 http://msdn.microsoft.com/en-us/library/ms740481%28v=VS.85%29.aspx http://msdn.microsoft.com/en-us/library/ms740481%28v=VS.85%29.aspx

Since you are in the blocking mode there still might be some data... 由于您处于阻止模式,因此仍然可能会有一些数据...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM