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