Jak przekazać dowolny adres IP i port aby połączyć się z socketem UDP?

0

Zainspirowany wątkiem postanowiłem sam napisać działanie na gnieździe UDP.

Próbuję napisać program do wysyłania wiadomości tekstowej i napisałem sobie program okienkowy do tego zadania i napotkałem pewien problem. Otóż mam dwa pola do wypełnienia
adres IP i port

screenshot-20221116211336.png

i teraz tak, gdy w pole z adresem IP wpiszę adres 127.0.0.1 i w pole z portem wpiszę dowolny numer portu, to przy pomocy qInfo wszystkie informacje mi się wyświetlają (zrzut niżej)

screenshot-20221116211535.png

natomiast gdy wpiszę zupełnie inny adres IP np 172.19.88.244 i jakiś numer portu to wcale nie chce mi się pokazać przy pomocy polecenia qInfo (zrzut niżej)

screenshot-20221116211816.png
dane do połączenia z portem znajdują się w funkcji void MainWindow::setRemoteHostdata() i ta sama funkcja wyświetla też te powyższe dane na konsolę

cały kod wygląda tak

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    this->resize(400,300);

    mainWidget = new QWidget(this);

    mainLayout = new QVBoxLayout(mainWidget);

    lblIPv4 = new QLabel(this);
    lblIPv4->setText(QString(tr("Adres IP")));

    leIPv4 = new QLineEdit(this);
    leIPv4->setMaxLength(15);

    remoteHostIpAddress = new QHostAddress(); //tutaj tworzę obiekt który przechowuje adres IP do użytku z UDP

    lblPort = new QLabel(this);
    lblPort->setText(QString(tr("Port")));

    lePort = new QLineEdit(this);
    lePort->setMaxLength(5);

    remoteHostData = new QHBoxLayout();

    sendText = new QTextEdit(this);

    newUdpSocket = new QUdpSocket(this); //tutaj tworzę socket UDP

    buttonLayout = new QHBoxLayout();

    bttSend = new QPushButton(this);
    bttSend->setText(QString(tr("Wyślij wiadomość")));

    bttOpenFile = new QPushButton(this);
    bttOpenFile->setText(QString(tr("Wyślij plik")));

    bttClear = new QPushButton(this);
    bttClear->setText(QString(tr("Wyczyść pola")));

    bttConnect = new QPushButton(this);
    bttConnect->setText(QString(tr("Połącz")));

    bttExit = new QPushButton(this);
    bttExit->setText(QString(tr("Zamknij")));

    mainLayout->addLayout(remoteHostData);
    remoteHostData->addWidget(lblIPv4);
    remoteHostData->addWidget(leIPv4);
    remoteHostData->addWidget(lblPort);
    remoteHostData->addWidget(lePort);
    mainLayout->addWidget(sendText);
    mainLayout->addLayout(buttonLayout);
    buttonLayout->addWidget(bttSend);
    buttonLayout->addWidget(bttOpenFile);
    buttonLayout->addWidget(bttClear);
    buttonLayout->addWidget(bttConnect);
    buttonLayout->addWidget(bttExit);

    this->setCentralWidget(mainWidget);

    QObject::connect(leIPv4, &QLineEdit::textChanged, this, &MainWindow::setIPv4addr);
    QObject::connect(lePort, &QLineEdit::textChanged, this, &MainWindow::setPort);

    QObject::connect(bttClear, &QPushButton::clicked, leIPv4, &QLineEdit::clear);
    QObject::connect(bttClear, &QPushButton::clicked, lePort, &QLineEdit::clear);
    QObject::connect(bttClear, &QPushButton::clicked, this, &MainWindow::clearField);

    QObject::connect(bttConnect, &QPushButton::clicked, this, &MainWindow::ipv4Addr);
    QObject::connect(bttConnect, &QPushButton::clicked, this, &MainWindow::port);
    QObject::connect(bttConnect, &QPushButton::clicked, this, &MainWindow::setRemoteHostdata);

    QObject::connect(bttExit, &QPushButton::clicked, this, &QMainWindow::close);
}

MainWindow::~MainWindow()
{
}

void MainWindow::setPort(const QString &port) //pobieram numer portu z kontrolki
{
    this->_port = port.toInt();

//    qInfo()<< this->_port;
}

quint16 MainWindow::port() //zwracam numer portu z kontrolki
{
//    qInfo()<< this->_port;
    return this->_port;
}

void MainWindow::setIPv4addr(const QString &ipAddr) //pobieram adres IP z kontrolki
{
    remoteHostIpAddress->setAddress(ipAddr);

//    qInfo()<< remoteHostIpAddress->toString();
}

QHostAddress MainWindow::ipv4Addr() //zwracam adres IP
{
//    qInfo()<< remoteHostIpAddress->toString();
    return *this->remoteHostIpAddress;
}

void MainWindow::setRemoteHostdata() //w tej funkcji próbuję się połączyć z socketem
{
    this->newUdpSocket->bind(ipv4Addr(),port());

    if(newUdpSocket->isOpen()){
        qInfo()<<"połączono" << newUdpSocket->localAddress().toString() << "o porcie" << newUdpSocket->localPort();;
    }
    else{
        qInfo()<<"brak połączenia z adresem" << newUdpSocket->localAddress().toString() << "o porcie" << newUdpSocket->localPort();
        qInfo()<< newUdpSocket->error();
    }
}

void MainWindow::clearField()
{
    this->_port = 0;
    this->remoteHostIpAddress->clear();
}

czy powie mi ktoś gdzie tkwi błąd i co trzeba poprawić żeby było dobrze ? Swoją drogą co trzeba zrobić aby uzyskać connect z otwartym socketem udp ?

1

Problem polega na tym, że metodę isOpen wziąłeś z kapelusza i postanowiłeś uznać że ona odpowie ci na to czy bind się udał (jeszcze piszesz że nie udało się połączyć, a binda robisz, czyli całkiem inną operację xd). A isOpen dla socketów udp najpewniej zawsze zwraca fałsz.

0
enedil napisał(a):

Problem polega na tym, że metodę isOpen wziąłeś z kapelusza i postanowiłeś uznać że ona odpowie ci na to czy bind się udał (jeszcze piszesz że nie udało się połączyć, a binda robisz, czyli całkiem inną operację xd). A isOpen dla socketów udp najpewniej zawsze zwraca fałsz.

dlaczego z kapelusza ? Przecież tą metodę zawiera klasa QIODevice, a po tej klasie dziedziczy QAbstractSocket, a następnie QUdpSocket więc w moim mniemaniu powinno to działać poprawnie. No jest jeszcze metoda isValid ale ona zwraca wartość bool w sytuacji gdy socket udało się stworzyć, w moim przypadku zwraca true ale nawet jeśli, to i tak nie widzę w metodzie bind przekazanego dowolnego adresu IP, tylko i tak uparcie wchodzi 172.0.0.1

1

Ja nie mówię że się kod który używa isOpen na gnieździe UDP nie skompiluje, tylko że zapewne nie zadziała tak jak chcesz. A co do 127.0.0.1 - doczytaj u licha co robi bind.

0
enedil napisał(a):

Ja nie mówię że się kod który używa isOpen na gnieździe UDP nie skompiluje, tylko że zapewne nie zadziała tak jak chcesz. A co do 127.0.0.1 - doczytaj u licha co robi bind.

funkcja bind tworzy powiązanie adresu IP z numerem portu na utworzonym sockecie. Jak jakieś informacje przyjdą na utworzony socket, to wywołuje się slot readyRead aby odczytać dane które tam przyszły za pomocą datagramu będzie to funkcja QUdpSocket::readDatagram

jeszcze jedno, funkcja bind przydaje się do pisania serwerów czyli aby coś wysłać z jednego kompa na drugi to muszę w obu aplikacjach zrobić kod odpowiadający za serwer

uważam, że dobrze rozumiem, jak coś źle zrozumiałem, to niech ktoś mnie wyprowadzi z błędu. Czyli jak podaję na przykład inny adres IP niż localhost np 172.29.88.33 to funkcja powinna łyknąć taki adres i go wyświetlić.

0

musisz bindować do adresu lokalnego interfejsu lub 127.0.0.1 lub 0.0.0.0 żeby słuchać na wszystkich interfejsach
jeśli któryś interfejs wie że ma taki adres to powinno przejść, jak jesteś za NATem to musisz nasłuchiwać na lokalnym przydzielonym adresie

0
obscurity napisał(a):

musisz bindować do adresu lokalnego interfejsu lub 127.0.0.1 lub 0.0.0.0 żeby słuchać na wszystkich interfejsach
jeśli któryś interfejs wie że ma taki adres to powinno przejść, jak jesteś za NATem to musisz nasłuchiwać na lokalnym przydzielonym adresie

więc rozumiem, że zamiast wpisywać na sztywno adres ip do funkcji bind w stylu

this->newUdpSocket->bind(QHostAddress("172.29.44.55"),port()); //to jest źle

to trzeba zrobić jak niżej, to wtedy nasłuchuję czy coś przyszło tylko na interfejsie IPv4 wszystkie zakresy adresów IPv4 na konkretnym porcie ? Dobrze rozumiem co mi mówisz ?

this->newUdpSocket->bind(QHostAddress::AnyIPv4,1111); //to jest dobrze

jeżeli dobrze rozumiem, to wtedy wystarczy odebrać datagram i wyświetlić zawartość która przyszła ? (W tym przypadku byłby dowolny tekst jak na chacie).

1 użytkowników online, w tym zalogowanych: 0, gości: 1