Russian Qt Forum

Qt => Работа с сетью => Тема начата: Fregloin от Июль 10, 2012, 12:02



Название: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 10, 2012, 12:02
Задача: есть 2 сетевых карты на компе, есть 4 клиентских сокета.
Нужно привязать 2 сокета на одну карту и 2 других сокета на другую картру.
Как это сделать?
+ Проверка, если нет 2 карт, соединяться через доступную.
+ абстрагирование от конкретного сетевого интерфейса (eth0,eth1 и в винде хз какие) так как по может работать и под вин и под лин.

Ну на счёт абстракции просто использовать индексы карт 0,1,2...
А вот как привязать сокет к конкретной сетевой карте?


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: mutineer от Июль 10, 2012, 12:09
может унаследоваться от сокета и использовать
Код:
void QAbstractSocket::setLocalAddress ( const QHostAddress & address ) [protected]
?


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 10, 2012, 12:13
хм, а что это даст? суть в том, что по двум сетевухам подключены 2 разных физических сети (для надёжности передачи данных),и если одна из них загибается, то данные будут идти со второй.
А так, неизвестно какой сокет к какой сетевухе ОС привяжет.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: DmitryM от Июль 10, 2012, 14:13
хм, а что это даст? суть в том, что по двум сетевухам подключены 2 разных физических сети (для надёжности передачи данных),и если одна из них загибается, то данные будут идти со второй.
А так, неизвестно какой сокет к какой сетевухе ОС привяжет.
Посмотри на вывод ifconfig и подумай  ;D


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 10, 2012, 18:56
посмотрел, и что? я не улавливаю ход ваших мыслей (


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Serr500 от Июль 10, 2012, 20:38
хм, а что это даст? суть в том, что по двум сетевухам подключены 2 разных физических сети (для надёжности передачи данных),и если одна из них загибается, то данные будут идти со второй.
А так, неизвестно какой сокет к какой сетевухе ОС привяжет.
Обычно у каждой сетевой карты свой IP-адрес. Привязка сокета к адресу автоматически привязывает его к определённому физическому устройству. Если же карты объединены в кластер и имеют единственный IP-адрес, то высокоуровневые функции, которые используются в Qt не позволят выбирать конкретную карту в любом случае.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 10, 2012, 20:49
хм, а что это даст? суть в том, что по двум сетевухам подключены 2 разных физических сети (для надёжности передачи данных),и если одна из них загибается, то данные будут идти со второй.
А так, неизвестно какой сокет к какой сетевухе ОС привяжет.
Обычно у каждой сетевой карты свой IP-адрес. Привязка сокета к адресу автоматически привязывает его к определённому физическому устройству. Если же карты объединены в кластер и имеют единственный IP-адрес, то высокоуровневые функции, которые используются в Qt не позволят выбирать конкретную карту в любом случае.
Тут речь об исходящем соединении (QTcpSocket), а ты говоришь о бинде сервера на определенный интерфейс.

Fregloin, ответ на поставленный вопрос: никак.
За выбор того или иного пути отвечает протокол, поэтому прикладной уровень не может на это влиять.
Поэтому твою задачу должен решать администратор сети. А твое ПО лишь должно диагностировать обрыв канала.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Serr500 от Июль 10, 2012, 21:08
Тут речь об исходящем соединении (QTcpSocket), а ты говоришь о бинде сервера на определенный интерфейс.
Упс... Что-то я невнимателен сегодня. Устал. Извиняюсь. Почему-то решил, что там listen, а не connect.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Serr500 от Июль 10, 2012, 21:21
Хм...  :-\ А вот что сказано в MSDN:
Цитировать
The bind function may also be used on an unconnected socket before subsequent calls to the connect, ConnectEx, WSAConnect, WSAConnectByList, or WSAConnectByName functions before send operations.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx)
Так что bind перед connect, кажется, привяжет сокет к локальному адресу.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: DmitryM от Июль 10, 2012, 23:12
Fregloin, ответ на поставленный вопрос: никак.
Каждому сетевому интерфейсу соответствует свой ip адрес. Сокет привязывается к адресу и порту, поэтому
Код
C++ (Qt)
void QAbstractSocket::connectToHost ( const QHostAddress & address, quint16 port, OpenMode openMode = ReadWrite )
 


За выбор того или иного пути отвечает протокол, поэтому прикладной уровень не может на это влиять.
Пример сервер имеет eth0 с ip 192.168.0.1 eth1 с ip 192.168.0.64
Пингую 192.168.0.1, пинг прошел, посылаю запрос 192.168.0.1.
если пинг на 192.168.0.1 не прошел, то посылаю запрос на 192.168.0.64.
В чем проблема?


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 10, 2012, 23:43
Fregloin, ответ на поставленный вопрос: никак.
Каждому сетевому интерфейсу соответствует свой ip адрес. Сокет привязывается к адресу и порту, поэтому
Код
C++ (Qt)
void QAbstractSocket::connectToHost ( const QHostAddress & address, quint16 port, OpenMode openMode = ReadWrite )
 


За выбор того или иного пути отвечает протокол, поэтому прикладной уровень не может на это влиять.
Пример сервер имеет eth0 с ip 192.168.0.1 eth1 с ip 192.168.0.64
Пингую 192.168.0.1, пинг прошел, посылаю запрос 192.168.0.1.
если пинг на 192.168.0.1 не прошел, то посылаю запрос на 192.168.0.64.
В чем проблема?
В том, что ты не понимаешь суть дела.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 10, 2012, 23:56
Хм...  :-\ А вот что сказано в MSDN:
Цитировать
The bind function may also be used on an unconnected socket before subsequent calls to the connect, ConnectEx, WSAConnect, WSAConnectByList, or WSAConnectByName functions before send operations.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx (http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550%28v=vs.85%29.aspx)
Так что bind перед connect, кажется, привяжет сокет к локальному адресу.
Да, видимо это все таки возможно, если делать ручками (android же как-то умеет использовать тот или другой интефейс), но средствами qt пока нет.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: DmitryM от Июль 11, 2012, 09:56
Да, видимо это все таки возможно, если делать ручками (android же как-то умеет использовать тот или другой интефейс), но средствами qt пока нет.
Привязка осуществляется к ip адресу, переключение идет на уровне TCP/IP при наличие более одного маршрута.



Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Akon от Июль 11, 2012, 10:42
Ответ на изначальный вопрос во втором посте. Еще вариант - создать нативный сокет, прибиндить его на желаемый сетевой интерфейс и сделать setSocketDescriptor().


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Serr500 от Июль 11, 2012, 11:04
Во втором посте ответ неверный.
Цитировать
void QAbstractSocket::setLocalAddress ( const QHostAddress & address ) [protected]

You can call this function in a subclass of QAbstractSocket to change the return value of the localAddress() function after a connection has been established. This feature is commonly used by proxy connections for virtual connection settings.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 11, 2012, 11:28
Ответ на изначальный вопрос во втором посте. Еще вариант - создать нативный сокет, прибиндить его на желаемый сетевой интерфейс и сделать setSocketDescriptor().
Note that this function does not bind the local address of the socket prior to a connection (e.g., QUdpSocket::bind()).


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: DmitryM от Июль 11, 2012, 11:33
Ответ на изначальный вопрос во втором посте. Еще вариант - создать нативный сокет, прибиндить его на желаемый сетевой интерфейс и сделать setSocketDescriptor().
И как ты будешь биндить к инерфейсу? См. bind  (http://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%BA%D0%B5%D1%82%D1%8B_%D0%91%D0%B5%D1%80%D0%BA%D0%BB%D0%B8#bind.28.29)


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Serr500 от Июль 11, 2012, 12:02
Биндить нужно к адресу. Адрес привязан к интерфейсу. Следовательно, сокет будет привязан к интерфейсу.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Akon от Июль 11, 2012, 12:52
Во втором посте ответ неверный.
Цитировать
void QAbstractSocket::setLocalAddress ( const QHostAddress & address ) [protected]

You can call this function in a subclass of QAbstractSocket to change the return value of the localAddress() function after a connection has been established. This feature is commonly used by proxy connections for virtual connection settings.
Цитировать
Цитата: Akon от Сегодня в 10:42
Ответ на изначальный вопрос во втором посте. Еще вариант - создать нативный сокет, прибиндить его на желаемый сетевой интерфейс и сделать setSocketDescriptor().
Note that this function does not bind the local address of the socket prior to a connection (e.g., QUdpSocket::bind()).
Из этого я могу сделать твердый вывод лишь о том, что localAddress() будет возвращать реальное значение только после того, как произойдет коннект, поскольку до коннекта системный сокет не создается. Впрочем, я очень допускаю, что установленное значение localAddress не используется в bind'e, и то, что setLocalAddress() не паблик - тому аргумент. Для выяснения этого нужно смотреть, что подается в системный bind.

Тем не менее, всегда есть вариант "создать нативный сокет, прибиндить его на желаемый сетевой интерфейс и сделать setSocketDescriptor()." В частности, я так биндил мультикастовые сокеты.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: DmitryM от Июль 11, 2012, 13:20
В частности, я так биндил мультикастовые сокеты.
QHostAddress::Any?


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 11, 2012, 13:41
Биндить нужно к адресу. Адрес привязан к интерфейсу. Следовательно, сокет будет привязан к интерфейсу.
Ты напиши конкретный код на qt и сюда запости, тогда может перестанешь глупости писать.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Akon от Июль 11, 2012, 13:44
QHostAddress::Any?
Это значит на усмотрение системы - что будет мултикаст?

Цитировать
Ты напиши конкретный код на qt и сюда запости, тогда может перестанешь глупости писать.
На сетевом интерфейсе несколько сетевых адресов, в бинд подается один из их числа, после успешной привязки будет работа через данный интерфейс. В чем глупость?



Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 11, 2012, 13:53
QHostAddress::Any?
Это значит на усмотрение системы - что будет мултикаст?

Цитировать
Ты напиши конкретный код на qt и сюда запости, тогда может перестанешь глупости писать.
На сетевом интерфейсе несколько сетевых адресов, в бинд подается один из их числа, после успешной привязки будет работа через данный интерфейс. В чем глупость?
Запутался, кто что пишет. Я подумал, что сер00 пытается убедить, что setLocalAddress является решением.
Перечитал. Вроде уже во всем разобрались.
Средствами qt это сделать нельзя. Только ручками через bind.
А тред все еще продолжается  ???

Кстати извиняюсь, за "глупость".


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 25, 2012, 15:33
А как получить список установленных сетевых карт и их настроек.

Задача такова: на каждом клиенте есть две линии связи (две сетевых карты).
2 сокета должны подключаться через первую карту, 2 через вторую. Итого 4 сокета на 2 сетевые = 4 канала.
Подключение идет к 4м разным серверам (которые друг друга дублируют + кое какие ньюансы, но не берем в расчет).

Есть программа редактор. В ней создается проект и задаются его настройки (сетевые в частности).
В этих настройках задаю ip:port для каждого клиента.
Теперь нужно еще указывать индекс сетевой карты (от нуля до макс, но пока до 1, т.е. 2 сетевых). Так как в редакторе не известно какие сетевые адреса будут иметь карты на конечных машинах (да и не важно). Если сетевая карта одна, то все подключения будут идти через нее.
Т.е. мне нужно узнать сколько сетевых на конченой машине установлено, выудить их адреса и затем уже биндить сокет получается?



Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 25, 2012, 16:24
Теперь нужно еще указывать индекс сетевой карты (от нуля до макс, но пока до 1, т.е. 2 сетевых). Так как в редакторе не известно какие сетевые адреса будут иметь карты на конечных машинах (да и не важно). Если сетевая карта одна, то все подключения будут идти через нее.
Т.е. мне нужно узнать сколько сетевых на конченой машине установлено, выудить их адреса и затем уже биндить сокет получается
Я бы лучше для идентификации карт использовал не индекс и не IP, а mac-адрес.
Это все-таки более однозначно и не зависит от прочих обстоятельств,
чем ничего не значащее "сетевая карта 1" и "сетевая карта 2". Сразу вопросы будут возникать.

Т.е. мне нужно узнать сколько сетевых на конченой машине установлено, выудить их адреса и затем уже биндить сокет получается
Ну да. Вроде ж обсудили уже все.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 25, 2012, 17:27
ну макадрес... во первых я его могу не знать заранее, во вторых одинаковые конфигурации клиентов могут работать на нескольких разных машинах, а это получается нужно для каждой машины иметь отличные конфигурации что не есть хорошо


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: andrew.k от Июль 25, 2012, 17:57
ну макадрес... во первых я его могу не знать заранее, во вторых одинаковые конфигурации клиентов могут работать на нескольких разных машинах, а это получается нужно для каждой машины иметь отличные конфигурации что не есть хорошо
А если я сетевухи поменяю местами или винда их поменяет местами, то конфигурация работать уже не будет.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Июль 30, 2012, 12:51
я написал, что привязываться к мак-адресам не могу. да не особо принципиально.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Странник от Август 07, 2012, 10:21
к слову, в Qt 5 будет возможно использовать bind до connect:
Цитировать
Binding of TCP sockets
QTcpSocket can be bound to an IP address before connecting, which can be used to limit the connection to a specific interface in a multihomed environment.


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Январь 30, 2013, 15:35
SOCKET s = АПИ, создающая сокет
bind(s, желаемый сетевой интерфейс);
QTcpSocket qs;
ds.setSocketDescriptor(s);
ds.connectToHost(...);

взял с параллельной темы пример. setSocketDescriptor возвращает true, а реальный коннект с заданной сетевой не происходит - коннект идет с первой доступной сетеовой. если выдернуть кабель с первой карты, то конект идет со второй (с которой и надо). с чем это связанно я так и не понял


Название: Re: Как привязать QTcpSocket к конкретной сетевой плате?
Отправлено: Fregloin от Январь 30, 2013, 18:27
Получилось забиндиться по разным сетевым картам, код ниже, но не получаю события при потере связи (если выдергиваю шнурок с карты)

Код:
void     QRawClient::connectToServer()
{
    if(fsocket.state() != QAbstractSocket::UnconnectedState) return;

    fmustReconnect = true;
    if(connectionConfig().interfaceIndex()>=0)
    {
        if(!fbindAddress.isNull())   //если биндинг задан, создаем сокет посредством Qt
        {
            qDebug("Try bind %i:%s to %s",connectionConfig().interfaceIndex(),qPrintable(connectionConfig().host()),qPrintable(fbindAddress.toString()));

            int fd = fsocket.socketDescriptor();
            if(fd<0)
            {
                fd = socket(PF_INET,SOCK_STREAM,IPPROTO_TCP);
            }

            struct sockaddr_in bindAddr;

            memset(&bindAddr,0,sizeof(bindAddr));

            bindAddr.sin_family = PF_INET;
            bindAddr.sin_addr.s_addr = htonl(fbindAddress.toIPv4Address());

            if(bind(fd,(const struct sockaddr *)&bindAddr,sizeof(bindAddr))!=0)
            {
                qDebug("Socket bind to %s failed with reason %s",qPrintable(fbindAddress.toString()),strerror(errno));
                shutdown(fd,2);
#ifdef Q_WS_WIN32
closesocket(fd);
#else
                close(fd);
                return;
#endif
            }

            struct sockaddr_in connect_addr;
            memset(&connect_addr,0,sizeof(connect_addr));
            connect_addr.sin_family = PF_INET;
            connect_addr.sin_port = htons(connectionConfig().port());

            QHostAddress address(connectionConfig().host());
            connect_addr.sin_addr.s_addr = htonl(address.toIPv4Address());

            int connect_result = ::connect(fd,(const struct sockaddr *)&connect_addr,sizeof(connect_addr));
            qDebug("connect result %i",connect_result);
            if(connect_result==-1)
            {
                qDebug("connect error! %s",strerror(errno));
                close(fd);
                return;
            }
            else
            {
                bool bind_result = fsocket.setSocketDescriptor(fd,QAbstractSocket::ConnectedState);
                if(!bind_result)
                    qDebug("binding to native socket failed");
                else
                    qDebug("binding to native socket succsseeded");

                emit connectedToServer();
            }

            //fsocket.connectToHost(connectionConfig().host(),connectionConfig().port());
        }
    }
}

На ноуте где одна сетевая, при выдергивании сетевой я получаю событие о потере связи, а на двух сетевых нет...