Qt udp
От: milkpot Россия  
Дата: 02.02.23 15:49
Оценка:
Здравствуйте, есть приложение, использующее udp сокеты. В приложении bind с адресом AnyIPv4.
Также есть функция, посылающая в LocalHost данные в размере 72 байт в виде счётчика (по 64 байта).
Посылаемые данные представляют собой изображение, разбитое на блоки размером по 64 байта.
Изображение имеет размеры в 320х256 пикселов ( =81920 пикселов). Посылается 1280 блоков по 72 байта,
из которых данными являются 1280 блоков по 64 байта.
При посылке 1280 блоков по 72 байта принимается только 58304 байта (три четверти от посылаемых данных).
Вопрос: как добиться приема всей последовательности данных?

Фрагменты программного кода:

class Controller;
class Controller2;
class Window : public QWidget
{
    Q_OBJECT

public:
    Window();
    void appendtoLogListBox(const QString & );
    void /*HellowUDP*/writeToUdp(const QByteArray& qBinArray);
    void writeData(const QByteArray& qba);
    void gui_prepare_generate_data();
    QByteArray another_qba;
public slots:
    void displayImage(const QImage& );
    void launch();
    void processUdpData();
    void readPendingDatagrams();
    void setUdpData(const QByteArray& );
signals:
    void writeUdpData(const QByteArray & );
private:
    Helper helper;
    QImage img1;
    Controller *cntrl;
    Controller2 *cntrl_2;
    QUdpSocket *socket;
    QListWidget *listWidget;
    int i_counter;

};

QByteArray another_qba;

Window::Window()
{
    i_counter=0;
    int data_quant=81920;
    another_qba.resize(data_quant);

    connect(button_3,SIGNAL(clicked()),this,SLOT(processUdpData()));
    socket=new QUdpSocket(this);
    bool result;

    result=socket->bind(/*QHostAddress(QString("192.168.10.3" "127.0.0.1"))*/QHostAddress::AnyIPv4/*LocalHost*/,50011/*2*/);
    QString algostr;
    algostr=QString(tr("bind returned %1")).arg(result);
    qDebug() << algostr;
    qDebug() << result;
    if(result)
    {
        qDebug() << "PASS";
    }
    else
    {
        qDebug() << "FAIL";
        qDebug() << "error" << socket->error();
        qDebug() << socket->errorString().toLocal8Bit();
    }
   // do_send_result(algostr);
    connect(socket, &QUdpSocket::readyRead,this,&/*UDPresource*/Window::readPendingDatagrams);
    connect(this,&Window::writeUdpData,this,&Window::setUdpData);
}

void Window::displayImage(const QImage& img)
{
    img1=img;
    helper.img2=img1;
   // update();
   // qDebug() << "--- displayImage func";
    return;
}

void Window::readPendingDatagrams()
{
    int size_of_data=0;
    qint64 ret_value=0;
    QByteArray buffer;
    QString str;
    while(socket->hasPendingDatagrams())
    {
        size_of_data=socket->pendingDatagramSize();
        if(-1==size_of_data) continue;
        buffer.resize(socket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        ret_value=socket->readDatagram(buffer.data(),buffer.size(),&sender,&senderPort);
        if(-1==ret_value)
        {
            str=QString(tr("readDatagram failed"));
            qDebug() << str;
           // do_send_result(str);
            appendtoLogListBox(str);
            continue;
        }
//        qDebug() << "Message from: " << sender;
//        qDebug() << "Message port: " << senderPort;
        quint32 value; bool ok;
        value=sender.toIPv4Address(&ok);
        if(true==ok)
        {
            str=QString(tr("address is %1 port %2")).arg(value,0,16).arg(senderPort);
            //qDebug() << str;
        }
        emit writeUdpData(buffer);
        //qDebug() << "emit writeUdpData(buffer)";
    }
}


void Window::processUdpData()
{
    QByteArray qba1;
    QByteArray Data;
    Data.resize(72);

        Data[0]=0xFF;
        Data[1]=0x00;
        Data[2]=0x00;
        Data[3]=0x00;
        Data[4]=0x00;
        Data[5]=0x00;
        Data[6]=0x00;
        Data[7]=0x00;
        for(int i=0;i<64;i++)
            Data[i+8]=(u_char)i;
        for(int i=0;i<1280;i++)//81920 bytes 
        writeToUdp(Data);
    return;
}

void Window::writeToUdp(const QByteArray& qBinArray)
{
    QByteArray Data;
    QHostAddress address;
   // quint16 port;
    quint16 port_large;
    qint64 retData=0;
    QString str;

    port_large=50011/*50012*/;
    retData=socket->writeDatagram(qBinArray/*Data*/,/*address*/QHostAddress::LocalHost, port_large);
    if(-1==retData)
    {
        qWarning() << "Unable to write data to " << address.toString() << ":" << /*port*/port_large << endl;
        str=QString(tr("*** writeDatagram returned %1")).arg(retData);
        qDebug() << str;
        appendtoLogListBox(str);
    }
}




void Window::setUdpData(const QByteArray& qba)
{
    QString result;
    //result=QString(tr("--- Window _ setUdpData slot"));
    int data_quant=81920;
    //qDebug() << "receiveUdpData slot";
    for(int i=0;i<64;i++)
    {
        another_qba[i_counter]=qba[i+8];
        i_counter++;
    }
    if(i_counter==data_quant)
    {
        gui_prepare_generate_data();
        i_counter=0;
    }
        qDebug() << "i_counter" << i_counter;
    return;
}

void Window::gui_prepare_generate_data()
{
    QString str;
    QString filePath;
    QFile file;
    QDataStream dstrm;
    int n=0;
    int data_quant=0;
    std::vector<unsigned short> buffer_vect;
    QSize rct_size(320,256);

   // QPixmap myPixmap;

    QImage loc_img(rct_size,QImage::Format_RGB32 /*QImage::Format_RGBX8888*/);

    QRgb *line;

   // pixmap_vect.clear();

   // QBuffer hr;

    unsigned long/* long */ start_time=GetTickCount();

        for(int y=0;y<loc_img.height();y++)
        {
           // QRgb *line=reinterpret_cast<QRgb*>(loc_img.scanLine(y));
            line=static_cast<QRgb *>(static_cast<void *>(loc_img.scanLine(y)));
            for(int x=0;x<loc_img.width();x++)
            {
                line[x]=qRgb(another_qba[n],another_qba[n],another_qba[n]);
                n++;
            }
        }

        //img1=loc_img;
        displayImage(loc_img);

    unsigned long/* long */ end_time=GetTickCount();
    unsigned long/* long */ loc_delta=end_time-start_time;
   // loc_list.clear();
    return;
}
Re: Qt udp
От: пффф  
Дата: 02.02.23 15:55
Оценка: +1
Здравствуйте, milkpot, Вы писали:
M>При посылке 1280 блоков по 72 байта принимается только 58304 байта (три четверти от посылаемых данных).
M>Вопрос: как добиться приема всей последовательности данных?

Qt тут не причем. UDP не гарантирует доставку. Видимо, не влезает в буфера, и отбрасывается. Надо смотреть в сторону сокет опшнс, SO_*. Но если в общем случае размер суперблока данных произвольный, то это не поможет.

Не отсылать сразу все, отсылать с паузой, сделать паузу до подтверждения приема
Re: Qt udp
От: Pzz Россия https://github.com/alexpevzner
Дата: 03.02.23 19:00
Оценка:
Здравствуйте, milkpot, Вы писали:

M>При посылке 1280 блоков по 72 байта принимается только 58304 байта (три четверти от посылаемых данных).

M>Вопрос: как добиться приема всей последовательности данных?

Принимают их на венде?

У венды на UDP-сокете по умолчанию очень маленький приемный буфер, и его легко переполнить. См. в сторону SO_RCVBUF

Но UDP все равно не гарантирует надежной доставки, хоть 25% потерь, это, конечно, перебор. Зачем тебе UDP? Используй TCP и не ищи себе приключений.

M>Фрагменты программного кода:


Не буду я читать твой код, уж извини
Re: Qt udp
От: Skorodum Россия  
Дата: 06.02.23 09:13
Оценка: 3 (1)
Здравствуйте, milkpot, Вы писали:


M>void Window::readPendingDatagrams()

M>{
M> ...
M> QByteArray buffer;
M> ....
M> emit writeUdpData(buffer);
M> }
M>}
M>[/ccode]
Осторожнее: в случае если сигнал и слот в разных потоках или явного использования Qt::QueuedConnection в connect данные будут скопированы.

В общем случае сетевые операции и GUI лучше делать в разных потоках:
* отедельный поток случает сеть и записывает данные в кольцевой буфер
* потом отправляет сигнал-уведомление о новых данных
* GUI берет данные из кольцевого буфера

M>
M>void Window::setUdpData(const QByteArray& qba)
M>{
M>    QString result;
M>    //result=QString(tr("--- Window _ setUdpData slot"));
M>    int data_quant=81920;
M>    //qDebug() << "receiveUdpData slot";
M>    for(int i=0;i<64;i++)
M>    {
M>        another_qba[i_counter]=qba[i+8];
M>        i_counter++;
M>    }
M>    if(i_counter==data_quant)
M>    {
M>        gui_prepare_generate_data();
M>        i_counter=0;
M>    }
M>        qDebug() << "i_counter" << i_counter;
M>    return;
M>}
M>

Оператор [] у QByteArray (qba[i+8]) делает копию даннах, тут нужно qba.at(i+8)

З.Ы. Если все в рамках одной машины, то QLocalSocket может быть лучше.
Отредактировано 06.02.2023 11:32 Skorodum . Предыдущая версия .
Re[2]: Qt udp
От: milkpot Россия  
Дата: 07.02.23 13:32
Оценка:
Здравствуйте, Pzz, Вы писали:

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


M>>При посылке 1280 блоков по 72 байта принимается только 58304 байта (три четверти от посылаемых данных).

M>>Вопрос: как добиться приема всей последовательности данных?

Pzz>Принимают их на венде?


Pzz>У венды на UDP-сокете по умолчанию очень маленький приемный буфер, и его легко переполнить. См. в сторону SO_RCVBUF


Pzz>Но UDP все равно не гарантирует надежной доставки, хоть 25% потерь, это, конечно, перебор. Зачем тебе UDP? Используй TCP и не ищи себе приключений.


M>>Фрагменты программного кода:


Pzz>Не буду я читать твой код, уж извини


Программа выполняется под Windows.
При посылке данных я вставил задержку
        for(int i=0;i<1280;i++)//81920 bytes sent to worker thread
        {
        writeToUdp(Data/*const QByteArray& qBinArray*/);
            if(i%426!=0)
            {
                for(int j=0;j<4000;j++)0;
                //for(int j=0;j<4000;j++)0;
            }
            else
                ::Sleep(1);
        }

теперь все посланные данные принимаются.
Хотя скорее надо работать с размером приемного буфера.
От устройства идет Udp. По ТЗ должен быть Udp протокол.
Re[3]: Qt udp
От: Pzz Россия https://github.com/alexpevzner
Дата: 07.02.23 14:22
Оценка: 3 (1)
Здравствуйте, milkpot, Вы писали:

M>теперь все посланные данные принимаются.

M>Хотя скорее надо работать с размером приемного буфера.
M>От устройства идет Udp. По ТЗ должен быть Udp протокол.

Я принимал видеопоток на венде. По UDP. Чтобы добиться небольшого процента потерь, пришлось сделать буфер по-максимуму и задрать до потолка приоритет принимающей нити. Иначе при наличии более-менее заметной графической активности (напр, перетаскивание окошек с места на место) все равно время от времени принимающий поток мог терять процессор на единицы миллисекунд, и этого хватало, чтобы потерять часть пакетов.
Re[4]: Qt udp
От: milkpot Россия  
Дата: 08.02.23 15:15
Оценка:
Здравствуйте, Pzz, Вы писали:

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


M>>теперь все посланные данные принимаются.

M>>Хотя скорее надо работать с размером приемного буфера.
M>>От устройства идет Udp. По ТЗ должен быть Udp протокол.

Pzz>Я принимал видеопоток на венде. По UDP. Чтобы добиться небольшого процента потерь, пришлось сделать буфер по-максимуму и задрать до потолка приоритет принимающей нити. Иначе при наличии более-менее заметной графической активности (напр, перетаскивание окошек с места на место) все равно время от времени принимающий поток мог терять процессор на единицы миллисекунд, и этого хватало, чтобы потерять часть пакетов.


Получается, принимать и посылать данные надо в рабочей нити?
Re[5]: Qt udp
От: Pzz Россия https://github.com/alexpevzner
Дата: 08.02.23 16:06
Оценка:
Здравствуйте, milkpot, Вы писали:

M>Получается, принимать и посылать данные надо в рабочей нити?


Ну, посылать тебе может и не обязательно с такими требованиями.

Но я, да, имел отдельную нитку именно чтобы данные из UDP выгребать. Она работала с очень высоким приоритетом, но поскольку у нее не так уж и много было работы, особо не мешалась. Но разок, из-за моей ошибки, она зациклилась, в компьютере отвалилось практически всё.
Re: Qt udp
От: milkpot Россия  
Дата: 13.02.23 15:06
Оценка:
Здравствуйте, milkpot, Вы писали:

M>Здравствуйте, есть приложение, использующее udp сокеты. В приложении bind с адресом AnyIPv4.

M>Также есть функция, посылающая в LocalHost данные в размере 72 байт в виде счётчика (по 64 байта).
M>Посылаемые данные представляют собой изображение, разбитое на блоки размером по 64 байта.
M>Изображение имеет размеры в 320х256 пикселов ( =81920 пикселов). Посылается 1280 блоков по 72 байта,
M>из которых данными являются 1280 блоков по 64 байта.
M>При посылке 1280 блоков по 72 байта принимается только 58304 байта (три четверти от посылаемых данных).
M>Вопрос: как добиться приема всей последовательности данных?

M>Фрагменты программного кода:


M>
M>class Controller;
M>class Controller2;
M>class Window : public QWidget
M>{
M>    Q_OBJECT

M>public:
M>    Window();
M>    void appendtoLogListBox(const QString & );
M>    void /*HellowUDP*/writeToUdp(const QByteArray& qBinArray);
M>    void writeData(const QByteArray& qba);
M>    void gui_prepare_generate_data();
M>    QByteArray another_qba;
M>public slots:
M>    void displayImage(const QImage& );
M>    void launch();
M>    void processUdpData();
M>    void readPendingDatagrams();
M>    void setUdpData(const QByteArray& );
M>signals:
M>    void writeUdpData(const QByteArray & );
M>private:
M>    Helper helper;
M>    QImage img1;
M>    Controller *cntrl;
M>    Controller2 *cntrl_2;
M>    QUdpSocket *socket;
M>    QListWidget *listWidget;
M>    int i_counter;

M>};

M>QByteArray another_qba;

M>Window::Window()
M>{
M>    i_counter=0;
M>    int data_quant=81920;
M>    another_qba.resize(data_quant);

M>    connect(button_3,SIGNAL(clicked()),this,SLOT(processUdpData()));
M>    socket=new QUdpSocket(this);
M>    bool result;

    QVariant value1;
    value1=socket->socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption);
    qDebug() << "QVariant-value1 " << value1.toInt();
    value1=QVariant(100000);
    qDebug() << "QVariant-value1 " << value1.toInt();

M>    result=socket->bind(/*QHostAddress(QString("192.168.10.3" "127.0.0.1"))*/QHostAddress::AnyIPv4/*LocalHost*/,50011/*2*/);
M>    QString algostr;
M>    algostr=QString(tr("bind returned %1")).arg(result);
M>    qDebug() << algostr;
M>    qDebug() << result;
M>    if(result)
M>    {
M>        qDebug() << "PASS";
M>    }
M>    else
M>    {
M>        qDebug() << "FAIL";
M>        qDebug() << "error" << socket->error();
M>        qDebug() << socket->errorString().toLocal8Bit();
M>    }
M>   // do_send_result(algostr);
    socket->setSocketOption(QAbstractSocket::ReceiveBufferSizeSocketOption,value1);
    value1=socket->socketOption(QAbstractSocket::ReceiveBufferSizeSocketOption);
    qDebug() << "QVariant-value1 is " << value1.toInt();// равно 100000
M>    connect(socket, &QUdpSocket::readyRead,this,&/*UDPresource*/Window::readPendingDatagrams);
M>    connect(this,&Window::writeUdpData,this,&Window::setUdpData);
M>}


Теперь принимаются все 1280 блоков по 72 байта.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.