QUdpSocket неправильно отправляет сообщения с сервера на клиент - PullRequest
0 голосов
/ 22 февраля 2019

Я строю пользовательский интерфейс Сервер / Клиент.Чтобы воспроизвести проблему, я подготовил MVCE, который повторяет проблему, которая у меня есть.

Интерфейс GUI описывается следующим образом: серверный компьютер имеет QGraphicsView, где есть зеленый квадрат N.1, движущийся в пределах границ QGraphicsScene, и препятствие.Как только квадрат попадает либо в границы, либо в препятствие, серверный компьютер должен отправить клиенту сообщение с координатами столкновения.

Для запуска примера выполните следующие шаги:

1) установить номер порта на клиенте и сервере (номер порта должен быть одинаковым)

2) подготовить сообщение для отправки с сервера на клиент

3) подключить клиент

4) Отправить сообщение с сервера клиенту

5) Подождите, пока квадрат не достигнет границы или препятствия

6) Как только это произойдет, сервер долженотправить координаты столкновения клиенту.(Я застрял в этом последнем пункте)

См. Рисунок ниже, который описывает

server/client

Что я пытался до сих пор :

Похоже, что с этого сообщения должен быть приоритет сообщений, отправляемых с / на серверный компьютер.Однако я могу успешно отправлять сообщения с сервера на клиент.

Также в соответствии с этот источник , чтобы не потерять информацию о том, что должно быть установлено более одной дейтаграммы.

Дополнительно всегда из того же поста UDP против TCP может быть основной причиной потери данных.

См. Ниже код, который повторяет проблему :

Клиент UDP

widget.h

namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_connectBtn_clicked();
private:
    Ui::Widget *ui;
    QUdpSocket *mSocket;
};
#endif // WIDGET_H

widget.cpp

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    mSocket = new QUdpSocket(this);
    setWindowTitle("Client Machine");
    connect(mSocket, &QUdpSocket::readyRead, [&]() {
       if(mSocket->hasPendingDatagrams()) {
           QByteArray datagram;
           datagram.resize(mSocket->pendingDatagramSize());
           mSocket->readDatagram(datagram.data(), datagram.size());
           ui->listWidget->addItem(QString(datagram));
       }
    });
}

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

void Widget::on_connectBtn_clicked()
{
    mSocket->bind(ui->portSpinBoxClient->value(), QUdpSocket::ShareAddress);
}

UDP-сервер

widget.h

#include <QWidget>
#include <QGraphicsItem>
namespace Ui {
class Widget;
}
class QUdpSocket;
class Widget : public QWidget
{
    Q_OBJECT
public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void on_sendBtn_clicked();
    void on_pushButton_clicked();
private:
    Ui::Widget *ui;
    QUdpSocket *mSocket;
    QGraphicsScene *scene;
    QTimer *timer;
    QGraphicsRectItem *itemRect;
#endif // WIDGET_H

widget.cpp

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    mSocket = new QUdpSocket(this);
    setWindowTitle("Server Machine");

    scene = new QGraphicsScene(this);
    itemRect = new QGraphicsRectItem();

    ui->graphicsView->setScene(scene);
    ui->graphicsView->setRenderHint(QPainter::Antialiasing);
    scene->setSceneRect(-200, -200, 300, 300);

    QBrush darkBrush(Qt::darkRed);
    QPen darkRedPen(Qt::darkRed);
    itemRect = scene->addRect(-100, -100, 30, 100, darkRedPen, darkBrush);
    itemRect->setFlag(QGraphicsItem::ItemIsMovable);

    QPen myPen = QPen(Qt::red);
    QLineF TopLine(scene->sceneRect().topLeft(), scene->sceneRect().topRight());
    QLineF LeftLine(scene->sceneRect().topLeft(), scene->sceneRect().bottomLeft());
    QLineF RightLine(scene->sceneRect().topRight(), scene->sceneRect().bottomRight());
    QLineF Bottom(scene->sceneRect().bottomLeft(), scene->sceneRect().bottomRight());

    scene->addLine(TopLine, myPen);
    scene->addLine(LeftLine, myPen);
    scene->addLine(RightLine, myPen);
    scene->addLine(Bottom, myPen);

    int itemCount = 1;
    for(int i = 0; i < itemCount; i++) {
        MyItem *item = new MyItem();
        scene->addItem(item);
    }
    timer = new QTimer(this);
    connect(timer, SIGNAL(timeout()), scene, SLOT(advance()));
    timer->start(100);
    ui->pushButton->setStyleSheet("QPushButton{ background-color: grey }");
}

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

void Widget::on_sendBtn_clicked()
{
    auto datagram = ui->msgLineEdit->text().toLatin1();
    mSocket->writeDatagram(datagram, QHostAddress::Broadcast,ui->spinBox->value());
}

void Widget::on_pushButton_clicked()
{
    ui->pushButton->setStyleSheet("QPushButton{ background-color: green }");
    ui->pushButton->setText("Stop");
}

И, наконец, класс, в котором обнаруживаются сталкивающиеся объекты:

myitem.h

class MyItem : public QGraphicsItem
{
public:
    MyItem();
    QRectF boundingRect() const;
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
protected:
    void advance(int phase);
private:
    qreal angle;
    qreal speed;
    void doCollision();
};

#endif // MYITEM_H

myitem.cpp

#include "myitem.h"
MyItem::MyItem()
{
    angle = (qrand() % 360);
    setRotation(angle);
    speed = 5;
    int startX = 0;
    int startY = 0;
    if((qrand() % 1)){
        startX = (qrand() % 200);
        startY = (qrand() % 200);
    }else{
        startX = (qrand() % -100);
        startY = (qrand() % -100);
    }
    setPos(mapToParent(startX, startY));
}

QRectF MyItem::boundingRect() const
{
    return QRect(0, 0, 30, 30);
}

void MyItem::paint(QPainter *painter,
                   const QStyleOptionGraphicsItem *option,
                   QWidget *widget)
{
    QRectF rec = boundingRect();
    QBrush brush(Qt::gray);
    if(scene()->collidingItems(this).isEmpty()){
        brush.setColor(Qt::green); // no collision
    }else{
        brush.setColor(Qt::red);  // yes collision
        doCollision();
    }
    painter->fillRect(rec, brush);
    painter->drawRect(rec);
}

void MyItem::advance(int phase)
{
    if(!phase) return;
    QPointF location = this->pos();
    setPos(mapToParent(0, -(speed)));
}

void MyItem::doCollision()
{
    if((qrand() %1)) {
        setRotation(rotation() + (180+(qrand() % 10)));
    }else{
        setRotation(rotation() + (180+(qrand() % -10)));
    }
    // see if the new position is in bounds
    QPointF newPoint = mapToParent(-(boundingRect().width()), -(boundingRect().width() + 2));
    if(!scene()->sceneRect().contains((newPoint))){
        newPoint = mapToParent(0, 0); // move it back in bounds
    }else{
        setPos(newPoint); // set new position
    }
}

Ожидаемый результат : После того, как зеленый квадрат достигнет границ QGraphicsScene или объекта, координаты столкновения должны быть отправлены клиенту.

Фактический результат : Как отправить координаты столкновения вКлиент?

Есть идеи о том, какДля решения этой проблемы было бы очень полезно.

...