Как контролировать время ожидания соединения с Winsock API?

Я пишу программу с использованием Winsock API, потому что мой друг хотел, чтобы простая программа проверила и проверила, работает сервер Minecraft или нет. Он работает нормально, если он работает, однако, если он не работает, программа зависает до тех пор, пока, я предполагаю, не истечет время ожидания соединения. Еще одна проблема, если у меня есть что-то вроде этого (псевдокод):

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

кажется, что пропущено право на попытку Connection(), полностью игнорируя то, что выше. Я замечаю это, потому что программа зависнет, но она не изменит метку на "Соединение".

Вот мой фактический код подключения:

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 Form Application
Я использую Microsoft Visual C++ 2008 Express Edition

2 ответа

Решение

Ваш код не пропускает обновление метки. Обновление просто включает в себя выдачу оконных сообщений, которые еще не были обработаны, поэтому вы не видите новый текст перед подключением к сокету. Перед подключением к сокету вам придется прокачать очередь сообщений для новых сообщений.

Что касается самого сокета, то, к сожалению, в WinSock API нет тайм-аута подключения. У вас есть два варианта реализации тайм-аута вручную:

1) Предполагая, что вы используете блокирующий сокет (сокеты блокируются по умолчанию), выполните подключение в отдельном рабочем потоке.

2) Если вы не хотите использовать поток, переключите сокет в неблокирующий режим. Подключение сокета всегда завершается немедленно, поэтому ваш основной код не будет заблокирован, и вы получите уведомление позже, если подключение было успешным или нет. Есть несколько способов обнаружить это, в зависимости от того, какой API вы используете - WSAAsyncSelect(), WSAAsyncEvent() или select().

В любом случае, пока идет соединение, запустите таймер в вашем основном потоке. Если подключение выполнено успешно, остановите таймер. Если таймер истекает, отсоедините разъем, что приведет к прерыванию соединения с ошибкой.

Может быть, вы хотите прочитать здесь:

Чтобы гарантировать, что все данные отправляются и принимаются на подключенном сокете до его закрытия, приложение должно использовать shutdown для закрытия соединения перед вызовом closesocket. http://msdn.microsoft.com/en-us/library/ms740481%28v=VS.85%29.aspx

Так как вы находитесь в режиме блокировки, все еще могут быть некоторые данные...

Другие вопросы по тегам