Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Dimonira  
Дата: 06.05.19 13:19
Оценка:
Доброго дня!
Пишем софт на Qt (точнее, переписываем с си-шарпа), чтобы он работал и в Windows, и в Linux (AstraLinux).
Столкнулись с непонятным поведением кода, использующего сокеты, в Linux. В Windows всё работает отлично, но тот же код в Linux не работает.
Проблема, как выяснилось в привязке сокета к конкретному IP-адресу. У компьютера два (или более) сетевых интерфейса, поэтому в программе указывается локальный IP-адрес сетевого интерфейса, с которым надо работать.
Так вот, если в функции QUdpSocket.bind указать конкретный IP, то приёма UDP-пакетов нет, а если указать ANY, то приём есть. Как правильно привязать к конкретному IP?
qt bind socket
Re: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: -prus-  
Дата: 06.05.19 13:41
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Проблема, как выяснилось в привязке сокета к конкретному IP-адресу. У компьютера два (или более) сетевых интерфейса, поэтому в программе указывается локальный IP-адрес сетевого интерфейса, с которым надо работать.

D>Так вот, если в функции QUdpSocket.bind указать конкретный IP, то приёма UDP-пакетов нет, а если указать ANY, то приём есть. Как правильно привязать к конкретному IP?

Может попробовать что-то вроде
char* deviceName = "eth0";
setsockopt(QUdpSocket.socketDescriptor(), SOL_SOCKET, SO_BINDTODEVICE, deviceName, strlen(deviceName));

?
С уважением,
Евгений
Re: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Слава  
Дата: 06.05.19 14:08
Оценка: +1
Здравствуйте, Dimonira, Вы писали:

D>Так вот, если в функции QUdpSocket.bind указать конкретный IP, то приёма UDP-пакетов нет, а если указать ANY, то приём есть. Как правильно привязать к конкретному IP?


Вот сколько есть интерфейсов, столько и делайте udp-сокетов. Тупо, зато надёжно.
Re[2]: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Mr.Delphist  
Дата: 06.05.19 14:57
Оценка:
Здравствуйте, Слава, Вы писали:

С>Вот сколько есть интерфейсов, столько и делайте udp-сокетов. Тупо, зато надёжно.


Ничего тупого — так и надо поступать в свете "strong/weak host model". Более того, часть интерфейсов может быть VPN-туннелями, может быть вовлечение мультикастов с их автовыборами дефолтного слушателя, да мало ли что может быть вообще, особенно если сетевой адаптер является USB-донглом и может выниматься-вставляться по ходу дела.
Re[2]: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Dimonira  
Дата: 06.05.19 15:40
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, Dimonira, Вы писали:


D>>Так вот, если в функции QUdpSocket.bind указать конкретный IP, то приёма UDP-пакетов нет, а если указать ANY, то приём есть. Как правильно привязать к конкретному IP?


С>Вот сколько есть интерфейсов, столько и делайте udp-сокетов. Тупо, зато надёжно.

Причём тут количество сокетов? Вопрос в том как привязать сокет к конкретному интерфейсу.
Код, который работает без проблем в Windows, в Linux уже не работает:
void MyClass::Start()
{
    // Создаём сокет
    m_UdpSocket = new QUdpSocket(this);
    // Связываем сокет с локальным интерфейсом и портом приёма
    m_UdpSocket->bind(QHostAddress(m_Address), UDP_PORT);
    // Подключаем слот обработчика принятых датаграмм
    connect(m_UdpSocket, SIGNAL(readyRead()), this, SLOT(readDatagram()));
}
void MyClass::readDatagram()
{
    while(m_UdpSocket->hasPendingDatagrams())
    {
    //...
    }
}

Если вместо QHostAddress(m_Address) написать QHostAddress::Any, то приём начинается, но привязки то нет. А в Windows всё работает как написано.
Re: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 06.05.19 17:36
Оценка:
Здравствуйте, Dimonira, Вы писали:

Радикальный метод: покажите вывод strace операции bind() (или хотя бы сами его изучите). Тот ли адрес
передаётся?
Альтернативно: запустив программу, через netstat или ss посмотрите, на какой адрес завязался сокет.

Далее посмотрите на файрволл и настройки форвардинга. Может быть запрет на интерфейсе принимать пакеты на любые IP кроме IP этого интерфейса. Если форвардинг выключен, может не работать приём пакетов на один интерфейс для IP другого... по идее, в линуксе weak host model, но я не нагуглил, как это работает при выключенном форвардинге. Ещё есть rp_filter и другие более хитрые опции.
The God is real, unless declared integer.
Re[2]: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Dimonira  
Дата: 07.05.19 07:14
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, Dimonira, Вы писали:


N>Радикальный метод: покажите вывод strace операции bind() (или хотя бы сами его изучите). Тот ли адрес

N>передаётся?
N>Альтернативно: запустив программу, через netstat или ss посмотрите, на какой адрес завязался сокет.

N>Далее посмотрите на файрволл и настройки форвардинга. Может быть запрет на интерфейсе принимать пакеты на любые IP кроме IP этого интерфейса. Если форвардинг выключен, может не работать приём пакетов на один интерфейс для IP другого... по идее, в линуксе weak host model, но я не нагуглил, как это работает при выключенном форвардинге. Ещё есть rp_filter и другие более хитрые опции.


Сокет завязывается куда задали, пакеты в интерфейс приходят. Но программа их не берёт.

Вчера ещё попробовали в bind задать IP-адрес широковещательным, типа 10.10.255.255 — программа работает, приём есть. Но непонятно, нормально это или не очень.
Re[3]: Привязка сокета на PC с двумя адаптерами в Qt на Linux
От: Dimonira  
Дата: 07.05.19 09:26
Оценка:
Здравствуйте, Dimonira, Вы писали:

D>Здравствуйте, netch80, Вы писали:


N>>Здравствуйте, Dimonira, Вы писали:


N>>Радикальный метод: покажите вывод strace операции bind() (или хотя бы сами его изучите). Тот ли адрес

N>>передаётся?
N>>Альтернативно: запустив программу, через netstat или ss посмотрите, на какой адрес завязался сокет.

N>>Далее посмотрите на файрволл и настройки форвардинга. Может быть запрет на интерфейсе принимать пакеты на любые IP кроме IP этого интерфейса. Если форвардинг выключен, может не работать приём пакетов на один интерфейс для IP другого... по идее, в линуксе weak host model, но я не нагуглил, как это работает при выключенном форвардинге. Ещё есть rp_filter и другие более хитрые опции.


D>Сокет завязывается куда задали, пакеты в интерфейс приходят. Но программа их не берёт.


D>Вчера ещё попробовали в bind задать IP-адрес широковещательным, типа 10.10.255.255 — программа работает, приём есть. Но непонятно, нормально это или не очень.


Похоже и правда, дело в форвардинге. Принимается только на тот IP-адрес, которому посланы данные. У нас передавались данные широковещательно на 10.10.255.255, поэтому когда сокет привязали к 10.10.255.255, так всё и пошло.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.