Как контролировать время ожидания соединения с 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
Так как вы находитесь в режиме блокировки, все еще могут быть некоторые данные...