сокет c QT QUdp не отправляет / получает данные?

#c #qt #sockets #udp

#c #qt #сокеты #udp

Вопрос:

Согласно этой странице https://wiki.sa-mp.com/wiki/Query_Mechanism Я могу отправить некоторые данные хосту, и он ответит мне некоторой информацией, я прав? если нет, я был бы благодарен, если бы кто-нибудь мог мне в этом помочь.

Однако я выполняю приведенные ниже коды, но это просто ничего не делает O.O кто-нибудь знает, что я делаю неправильно?

 #include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QUdpSocket>
#include <qmessagebox.h>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QUdpSocket *mysock = new QUdpSocket(this);
    mysock->writeDatagram("i", QHostAddress("164.132.69.65"), 7777);
    QByteArray myarry;
    QHostAddress myhost;
    quint16 port;
    mysock->readDatagram(myarry.data(), myarry.size(), amp;myhost, amp;port);
    ui->textEdit->setText(myarry.data());
}

MainWindow::~MainWindow()
{
    delete ui;
}        
  

myarry.data() просто пустой ;-;….

Комментарии:

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

Ответ №1:

QUdpSocket::readDatagram() (и большинство функций сетевого ввода-вывода Qt) не блокируются до тех пор, пока данные не будут доступны. Это означает, что если вы вызовете его в момент, когда данные еще не поступили, у вас не будет никаких данных в предоставленном вами буфере, и вызов должен вернуться -1 .

Из документов:

readyRead() Сигнал выдается всякий раз, когда поступают дейтаграммы. В этом случае hasPendingDatagrams() возвращает true. Вызовите, pendingDatagramSize() чтобы получить размер первой ожидающей дейтаграммы и readDatagram() прочитать ее.

Вы должны вызывать readDatagram() из слота, который подключен к readyRead() сигналу.

 MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //mysock should be a member of the MainWindow class
    //so that you can access it from other functions
    mysock = new QUdpSocket(this);
    mysock->writeDatagram("i", QHostAddress("164.132.69.65"), 7777);
    connect(mysock, amp;QUdpSocket::readyRead, this, amp;MainWindow::readPendingDatagrams);
}

//add this slot to the class's declaration
void MainWindow::readPendingDatagrams(){
    //read datagrams in a loop to make sure that all received datagrams are processed
    //since readyRead() is emitted for a datagram only when all previous datagrams are read
    while(mysock->hasPendingDatagrams()){
        QByteArray datagram;
        datagram.resize(mysock->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        mysock->readDatagram(datagram.data(), datagram.size(),
                                amp;sender, amp;senderPort);

        //do whatever you want to received datagram
        ui->textEdit->setText(datagram.data());
    }
}
  

Редактировать:

Похоже, запрос, который вы отправляете на сервер, не соответствует спецификациям в вашей ссылке. В вашем коде вы просто отправляете "i" письмо и ничего больше.

На странице указано (вкратце), что вы должны отправить префикс, "SAMP" за которым следует ip сервера, затем порт сервера, после этого вы можете отправить свой код операции (который есть "i" в вашем случае).

Подводя итог, вот как я бы это реализовал:

 MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //mysock should be a member of the MainWindow class
    //so that you can access it from other functions
    mysock = new QUdpSocket(this);
    QHostAddress serverAddress("164.132.69.65");
    quint16 port= 7777;
    QByteArray data;
    //building request
    data = "SAMP";      //"SAMP" prefix
    //convert to big endian to make sure the octets are sent in the specified order
    quint32 ipv4AddrBigEndian= qToBigEndian(serverAddress.toIPv4Address());
    //convert to little endian to make sure port bytes are sent in the specified order
    quint16 portLittleEndian= qToLittleEndian(port);
    //add server ip address
    data.append(reinterpret_cast<char*>(amp;ipv4AddrBigEndian), sizeof(ipv4AddrBigEndian));
    //add server port
    data.append(reinterpret_cast<char*>(amp;portLittleEndian), sizeof(portLittleEndian));
    //add opcode
    data.append("i");
    mysock->writeDatagram(data, serverAddress, port);
    connect(mysock, amp;QUdpSocket::readyRead, this, amp;MainWindow::readPendingDatagrams);
}


void MainWindow::readPendingDatagrams(){
    //read datagrams in a loop to make sure that all received datagrams are processed
    //since readyRead() is emitted for a datagram only when all previous datagrams are read
    while(mysock->hasPendingDatagrams()){
        QByteArray datagram;
        datagram.resize(mysock->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        mysock->readDatagram(datagram.data(), datagram.size(),
                                amp;sender, amp;senderPort);

        qDebug() << "received: " << datagram.toHex();

        //do whatever you want to received datagram
        //you need to parse information you want from the datagram
        //It can NOT be just displayed as text in a QTextEdit (as it contains binary data)
    }
}
  

Формат двоичного ответа сервера, который вам нужно проанализировать, указан на странице, на которую вы ссылаетесь здесь.


Примечание сбоку:

Я действительно думаю, что вам следует отделить создание запросов и анализ ответов в их собственном классе, вместо того, чтобы иметь все это в MainWindow классе (который следует использовать для определения пользовательского интерфейса и ничего больше).

Комментарии:

1. Я пробовал ваш код, но readPendingDatagrams никогда не вызывается … :’c

2. Вы уверены, что другой конец действительно отправляет что-либо обратно? пожалуйста, используйте инструмент сниффера, такой как wireshark, чтобы подтвердить это. Вы используете UDP, нет никакой гарантии, что какой-либо хост действительно существует по адресу «164.132.69.65» и что он получил вашу отправленную дейтаграмму.

3. с хостом проблем нет, я уже создал приложение на c #, которое получает информацию без каких-либо проблем, оно просто отлично работает!, Idk что не так с c :’c