WINSOCK - Установка тайм-аута для попытки подключения по несуществующему IP? - PullRequest
17 голосов
/ 01 июня 2011

Я разрабатываю фильтр источника RTSP на C ++ и использую 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, все идет хорошо, но:

  1. Если мой фильтр создает сокет с существующим IP-адресом ,но на случайном порте, который никто не слушает, connect() ждет 3 секунды и возвращает WSAETIMEDOUT.Поэтому через 3 секунды я знаю, что предоставленный URL неверен.

  2. Если мой фильтр создает сокет с несуществующим IP-адресом и пытается подключиться к нему, он висит около 10 секунд перед возвратом SOCKET_ERROR.Итак, SO_RCVTIMEO игнорируется, если IP-адрес не существует в сети ...

ВОПРОС: Как установить время ожидания для несуществующегоIP, во втором случае?Нужно ли мне сначала отправлять ICMP PING, чтобы проверить, существует ли IP-адрес, или выполнить какую-либо другую проверку, подобную этой?

Любая помощь будет принята с благодарностью.Thanx.:)

ОТВЕТ НА МОЮ ПРОБЛЕМУ

Поскольку я использую блокирующие сокеты, вызывайте блоки connect(), пока не будет установлено соединение, или соединение не будет установлено, потому чтохост не отвечает или отказывается от соединения.Если я установлю тайм-аут сокета на 3 секунды и попытаюсь подключиться к несуществующему хосту, мой компьютер (клиент) отправит TCP-пакет с установленным флагом SYN, чтобы инициировать Threeway handshake ,Обычно хост, если он включен, ответит TCP-пакетом, содержащим установленные флаги ACK и SYN, а затем клиент (я) отправит TCP-пакет с установленным флагом ACK.Затем соединение установлено.НО, если хост не работает и отправлено SYN, клиент ждет, пока не истечет 3-секундный тайм-аут, а затем снова и снова пытается снова и снова, пока параметр реестра TcpMaxConnectRetransmissions ( MICROSOFT ARTICLE ) не станетдостигнут, потому что хост может быть UP, но пакет SYN может быть потерян ... Моя Windows XP имеет эту настройку на 4, я думаю, поэтому каждый раз, когда он пытается отправить SYN, он ждет 3 секунды, и когдачетвертая попытка не удалась, она возвращает SOCKET_ERROR (через 12 секунд) и устанавливает WSAETIMEDOUT в качестве последней ошибки WSA.

Обходной путь - использование неблокирующих сокетов и попытка вручную измерить соединениевремя попытки (потому что теперь connect() не будет блокироваться), как предложил Мартин Джеймс.

Другой способ - возиться с реестром, который является последним средством ...

Ответы [ 3 ]

2 голосов
/ 01 июня 2011

На самом деле сокеты Беркли не имеют тайм-аута для соединения, поэтому вы не можете установить его. ICMP PING не помогает, я не знаю почему, но если хост не существует, вы тратите около 1 секунды с PING. Попробуйте использовать ARP для обнаружения хоста.

2 голосов
/ 01 июня 2011

Укус пули.Удаленный IP-адрес может не работать на сервере PING или PING может быть заблокирован каким-либо маршрутизатором, поэтому это не поможет.Разве вы не можете просто подождать 10 секунд, а затем сделать какую-либо индикацию ошибки, которую вы используете?

Если вам абсолютно необходимо прервать попытку подключения через 3 секунды, вы можете сами установить время ожидания.

0 голосов
/ 04 апреля 2013

из cmd вы можете пропинговать ip с таким временем ожидания 'ping -w 100 -n 1 192.168.1.1'

он вернется в течение 100 мс

вы можете проверить код возвратапо 'echo% errorlevel% 0 = ok, 1 = fail, тогда вы знаете, стоит ли пытаться подключиться

в c ++

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