Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Определить, что передача по UDP завершена


Автор: Aoizora 11.2.2017, 23:14
Я пишу функцию для приложения, которая должна выполнять следующие задачи:

1. Соединиться с каждым из hardcoded клиентом p2p-сети
2. Послать ему запрос списка пиров, хранящегося в его локальной таблице
3. Принять пакеты, в поле данных каждого из которых находится информация о ноде
4. То же самое сделать со следующим элементом списка hardcoded серверов или вернуть управление из функции

У меня пока что такой код:

Код

#define arr_sz(a) (sizeof(a) / sizeof(a[0]))

static client_node bootstrap_list[] = 
{
    { 16777343, 39426, 0}    // ip = 127.0.0.1, port = 666, time = 0
};

void bootstrap(SOCKET sock)
{
    char packet[PACKET_SIZE] = { 0 };
    size_t list_size = arr_sz(bootstrap_list);

    for (size_t node_idx = 0; node_idx < list_size; ++node_idx)
    {
        pull_peer_list(sock, &bootstrap_list[node_idx]);
        while (recvfrom(sock, packet, PACKET_SIZE, 0, NULL, NULL) > 0)
        {
            // Process packet
        }
    }
}


Цикл по всем нодам, к каждой ноде выполняется запрос. Мне нужно как-то отсюда выйти, когда сервер перестанет посылать данные по UDP (или перейти к другому элементу списка). Как это сделать

Автор: tzirechnoy 11.2.2017, 23:41
По таймаутам.

Ну, ещё можно в сервере указать, когда последний пакет послан. Но по таймаутам -- абсолютно обязательно.

Автор: Aoizora 12.2.2017, 00:03
Цитата(tzirechnoy @ 11.2.2017,  23:41)
По таймаутам.

Ну, ещё можно в сервере указать, когда последний пакет послан. Но по таймаутам -- абсолютно обязательно.

По таймаутам - это вот так?

Код

static int recvfrom_timeout(SOCKET sock, long sec, long usec)
{
    struct timeval timeout;
    timeout.tv_sec = sec;
    timeout.tv_usec = usec;

    fd_set fds;
    FD_ZERO(&fds);
    FD_SET(sock, &fds);

    return select(0, &fds, 0, 0, &timeout);
}

void bootstrap(SOCKET sock)
{
    char packet[PACKET_SIZE] = { 0 };
    size_t list_size = arr_sz(bootstrap_list);

    for (size_t node_idx = 0; node_idx < list_size; ++node_idx)
    {
        pull_peer_list(sock, &bootstrap_list[node_idx]);
        while (recvfrom_timeout(sock, 10, 0) > 0)
        {
            recvfrom(sock, packet, PACKET_SIZE, 0, NULL, NULL);
            client_node peer;
            get_data(packet, &peer);
            printf("recvd peer\n");
            show_node_data(&peer);
        }
    }
}

Автор: _zorn_ 15.2.2017, 16:39
Что то типа этого делаешь ?  smile 
https://aminux.wordpress.com/2017/01/12/gov-torrents-download/

А по поводу кода - да, без селекта ВООБЩЕ НИКАК. Так по ублюдочному сделан стек в винде. 
recv будет висеть ВЕЧНО... Я тоже споткнулся об это. Ну по логике - нет данных, верни что прочитал (0,1 или 0.5 на крайняк smile) и отпусти ты дальше прогу выполняться, так нет же - до сих пор селект надо, даже если тебе пофиг или сам разрулишь если получил/принял меньше чем присылалось/отправлялось.
Причем такое даунское поведение именно тогда когда recv буфер пуст.

Автор: feodorv 17.2.2017, 05:27
Цитата(_zorn_ @  15.2.2017,  16:39 Найти цитируемый пост)
Так по ублюдочному сделан стек в винде. 
recv будет висеть ВЕЧНО... Я тоже споткнулся об это. Ну по логике - нет данных, верни что прочитал (0,1 или 0.5 на крайняк smile) и отпусти ты дальше прогу выполняться

Прежде чем так возмущаться перевести сокет в асинхронный режим не пробовали?

Автор: Олег2005 12.3.2017, 22:32
Или использовать IOCP?
На худой конец WSAEventSelect?

Автор: _zorn_ 15.3.2017, 16:32
Цитата(feodorv @  17.2.2017,  12:27 Найти цитируемый пост)

Прежде чем так возмущаться перевести сокет в асинхронный режим не пробовали? 

Так мне не нужен асинхронный. От колбеков и в яваскрипте тошнит. Хочу получить данные, обработать и дальше наслаждаться солнцем smile 
Уточню - наслаждение солнцем зависит от полученных данных.

Автор: feodorv 16.3.2017, 20:26
Честно говоря, я не знаю, что там в JavaScript с асинхронными сокетами - колбек или нет, да и причем он тут, если речь идёт о C/C++. Сокет можно перевести в асинхронный режим через FIONBIO, а затем пользовать read безо всяких колбеков. Но речь-то идёт об этой фразе:
Цитата(_zorn_ @  15.2.2017,  16:39 Найти цитируемый пост)
Так по ублюдочному сделан стек в винде. recv будет висеть ВЕЧНО...
Стек TCP/IP сделан так почти везде, и везде будет висеть recv() на блокирующем сокете, ожидая прихода данных. Я намекаю на то, что не стек виноват.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)