WINSOCK - установка тайм-аута для попытки подключения к не существующему IP-адресу?
Я разрабатываю фильтр источника RTSP в С++, и я использую WINSOCK 2.0 - блокирующий сокет.
Когда я создаю блокирующий сокет, я устанавливаю его SO_RCVTIMEO
на 3 секунды следующим образом:
int ReceiveTimeout = 3000;
int e = setsockopt(Socket, SOL_SOCKET, SO_RCVTIMEO, (char*)&ReceiveTimeout, sizeof(int));
Мой фильтр пытается подключиться к IP_ADDRESS:554
(554 - порт сервера RTSP). Если есть сервер, который прослушивает этот IP-адрес на порту 554, все идет хорошо, но:
-
Если мой фильтр создает сокет для существующего IP-адреса, но на случайном порту, который никто не слушает, connect()
ждет 3 секунды и возвращает WSAETIMEDOUT
. Итак, через 3 секунды я знаю, что предоставленный URL-адрес плох.
-
Если мой фильтр создает сокет для не существующего IP-адреса и пытается его подключить, он висит около 10 секунд перед возвратом SOCKET_ERROR. Таким образом, SO_RCVTIMEO
игнорируется, если IP не существует в сети...
Вопрос:
Как установить тайм-аут для не существующего IP-адреса во втором случае? Нужно ли сначала отправлять ICMP PING, чтобы увидеть, существует ли IP-адрес или выполнить какую-либо другую проверку?
Любая помощь будет оценена.
Thanx.:)
ОТВЕТ К МОЕЙ ПРОБЛЕМЕ
Поскольку я использую блокирующие сокеты, вызывайте блоки connect()
до тех пор, пока не будет установлено соединение, или соединение не будет выполнено, потому что хост не отвечает, или он отказывается от соединения. Если я установил тайм-аут сокета на 3 секунды и попытаюсь подключиться к хосту, который не существует, мой компьютер (клиент) отправит TCP-пакет с установленным флагом SYN
, чтобы инициировать рукопожатие Threeway. Обычно хост, если вверх, будет отвечать TCP-пакетом, содержащим флаги ACK
и SYN
, а затем клиент (я) отправит TCP-пакет с установленным флагом ACK
. Затем соединение выполняется. НО, если хост опущен и отправлен SYN
, клиент ждет, пока истечет 3-секундный тайм-аут, а затем попробует AGAIN и AGAIN, пока TcpMaxConnectRetransmissions
(MICROSOFT ARTICLE), поскольку хост может быть UP, но пакет SYN
может потеряться... Моя Windows XP имеет этот параметр в 4, я думаю, поэтому каждый раз, когда он пытается для отправки SYN
, он ждет 3 секунды, а когда четвертая попытка не удалась, он возвращает SOCKET_ERROR
(через 12 секунд) и устанавливает WSAETIMEDOUT
в качестве последней ошибки WSA.
Способ использования неблокирующих сокетов и попытка вручную измерить время попытки соединения (потому что теперь connect()
не будет блокироваться), как предположил Мартин Джеймс.
Еще один способ - возиться с реестром, который является последним средством...
Ответы
Ответ 1
Укусите пулю. На удаленном IP-адресе может не работать PING-сервер или PING может быть заблокирован каким-либо маршрутизатором, поэтому он не поможет. Можете ли вы не просто подождать 10 секунд, а затем сделать любую ошибку, которую вы используете?
Если вам понадобится тайм-аут попытки подключения через 3 секунды, вы можете сами это сделать.
Rgds,
Мартин
Ответ 2
На самом деле, у сокетов Berkeley нет таймаута для подключения, поэтому вы не можете его установить.
ICMP PING не помогает, я не знаю почему, но если хост не существует, вы тратите около 1 секунды на PING. Попробуйте использовать ARP для обнаружения, существует хост.
Ответ 3
из cmd вы можете ping ip с таймаутом, подобным этому 'ping -w 100 -n 1 192.168.1.1'
он вернется в пределах 100 мс
вы можете проверить код возврата на "echo% errorlevel% 0 = ok, 1 = fail, тогда вы знаете, если вы должны попробовать подключиться
в С++
bool pingip_nowait(const char* ipaddr)
{
DWORD exitCode;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
si.wShowWindow = SW_HIDE;
CString cmd = "ping -w 100 -n 1 ";
cmd += ipaddr;
if (!CreateProcess(NULL,
cmd.GetBuffer(),
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi)) {
TRACE("ERROR: Cannot launch child process\n");
return false;
}
// Give the process time to execute and finish
WaitForSingleObject(pi.hProcess, 200L);
if (GetExitCodeProcess(pi.hProcess, &exitCode))
{
TRACE("ping returned %d\n", exitCode);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exitCode==0 ? true : false;
}
TRACE("GetExitCodeProcess() failed\n");
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return false;
}