Russian Qt Forum

Qt => Работа с сетью => Тема начата: SibBear от Апрель 06, 2013, 20:35



Название: Взаимодействие по локалке
Отправлено: SibBear от Апрель 06, 2013, 20:35
Добрый день. Есть программа, установленная на нескольких компьютерах, которая следит за состоянием оборудования. Как средствами Qt сделать так, чтобы программа в определенных случаях отсылала сообщение своим копиям, которые, в свою очередь, выводили бы сообщение? Проблема в том, что локалка нестабильна и часто падает. Требуется проверять состояние раз в несколько секунд. Очень желательно, чтобы в случае отсутствия сети программа знала об этом мгновенно, а не пыталась подключиться в течение 30-40 секунд. Спасибо.
P.S. В сетевых делах ничего не соображаю, дайте направление, куда копать.


Название: Re: Взаимодействие по локалке
Отправлено: Странник от Апрель 06, 2013, 21:46
просили направление - пожалуйста.
http://en.wikipedia.org/wiki/Keepalive
поищите в документации QAbstractSocket::KeepAliveOption.


Название: Re: Взаимодействие по локалке
Отправлено: SibBear от Апрель 06, 2013, 21:57
Спасибо!


Название: Re: Взаимодействие по локалке
Отправлено: Bepec от Апрель 08, 2013, 15:44
Присоединюсь к вопросу.

Задача похожая - проверять доступность клиентов.

Бьюсь со связкой QTcpServer - QTcpSocket.

Socket корректно отрабатывает разрыв связи и пытается переподключаться.

Сервер же абсолютно игнорирует уже принятые соединения.

Попытка при newConnection вязать сокет с слотами ошибок и изменения состояний = бесполезно.

К тому же keepAlive вроде по умолчанию с таймаутом на 2 часа...

PS дежа вю. Я такую тему раньше не создавал?

update: Быстрый поиск дал http://www.prog.org.ru/topic_15945_0.html. Буду копать завтра. О результатах отпишусь.


Название: Re: Взаимодействие по локалке
Отправлено: Странник от Апрель 08, 2013, 16:11
К тому же keepAlive вроде по умолчанию с таймаутом на 2 часа...
настройка таймаутов потребует написания нескольких строк платформозависимого кода для каждой из целевых платформ.


Название: Re: Взаимодействие по локалке
Отправлено: Bepec от Апрель 09, 2013, 08:13
Спасибо за подсказку, по ссылке приведённой ранее уже имеется решение :D

Действительно, нужно писать платформозависимый код.

Под windows:
Код:
// подключаем Ws2_32.lib в проект (иначе будут unresolved'ы)

#include <winsock2.h> // библиотека работы с портами

// не нашёл константы на msdn. Кому интересно привожу ссылку
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx. Видимо часть библиотеки windows. :)
#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)


// собственно сама управляющая структура
struct tcp_keepalive {
u_long onoff; // включение /отключение
u_long keepalivetime; // время жизни
u_long keepaliveinterval; // время повторного запроса.
};


// этот кусок уже внутри слота connected(). Выполняется только при уже установленном подключении.
{
    //  pClientSocket - заменить на ваш QTcpSocket
    DWORD dwError = 0L,dwBytes ;
    tcp_keepalive pClSock_tcpKeepalive={0}, sReturned = {0};

    // заполняем структуру
    pClSock_tcpKeepalive.onoff=1;//включить keepalive
    pClSock_tcpKeepalive.keepalivetime=1000;// каждую "1.000" секунду отсылать пакет
    pClSock_tcpKeepalive.keepaliveinterval=1500;// Если не пришел ответ выслать через 1.5с повторно

    if (WSAIoctl(pClientSocket->socketDescriptor(), SIO_KEEPALIVE_VALS, &pClSock_tcpKeepalive,
    sizeof(pClSock_tcpKeepalive), &sReturned, sizeof(sReturned), &dwBytes,
    NULL, NULL) != 0)
    {
    dwError = WSAGetLastError() ;
    qWarning((char*)dwError);
    }
}

PS сделано на основании выкладки Orfus. Оригинал http://www.prog.org.ru/topic_15945_0.html.

PPS если начинает материться после включения winsock2.h, значит где-то ранее подключена windows.h и они конфликтуют.

Лечится включение только winsock2.h (он тянет за собой windows.h) или же #define WIN32_LEAN_AND_MEAN, который разруливает эту ситуацию.


Название: Re: Взаимодействие по локалке
Отправлено: Странник от Апрель 09, 2013, 10:59
POSIX версия в общих чертах выглядит примерно так. Windows тоже имеет реализацию setsockopt, но на практике не проверял.
Код
#include <sys/socket.h>
#include <netinet/tcp.h>
 
void setKeepAlive(int socketDescriptor, int state, int idle, int interval)
{
  setsockopt(socketDescriptor, SOL_SOCKET, SO_KEEPALIVE, (void*)&state, sizeof(state));
  setsockopt(socketDescriptor, SOL_TCP, TCP_KEEPIDLE, (void*)&idle, sizeof(idle));
  setsockopt(socketDescriptor, SOL_TCP, TCP_KEEPINTVL, (void*)&interval, sizeof(interval));
}
где state == 0 - отключить keepalive, 1 - включить
idle - время простоя соединения перед началом отправки keepalive-пакетов
interval - время задержки между keepalive-пакетами