• 12586阅读
  • 13回复

[提问]QT 实现屏幕共享,udp  丢包的问题 [复制链接]

上一主题 下一主题
离线crs811
 

只看楼主 倒序阅读 楼主  发表于: 2014-01-18
大家好,我在做一个QT UDP 发送数据的程序,遇到了严重的丢包问题,无论将发送大小改多少,都会丢包(本机测试时),请大家帮忙看看是怎么回事呢?
/*发送方*/
///////////////////////////////////////////////
UDPServer.cpp

loadSize = 8*1024;  //每次发送数据的大小 :8KB
udpSocket = new QUdpSocket(this);

void UDPServer::sendData()
{

    file.setFileName("D:/1.jpg");//大约150 KB

    i=1;
        ui->lstInfo->addItem("▼ begin send data");

    //循环传输文件数据
        while (!file.atEnd())
        {
            QByteArray line = file.read(loadSize);
            udpSocket->writeDatagram( line , QHostAddress::Broadcast, 7755 );

            ui->lstInfo->addItem(QString::number(i++) + " " +
                             QString::number(line.size()));
        }
        ui->lstInfo->addItem("▲ end send data");
}


/**************************************************************************************
/*接收方*/
///////////////////////////////////////////////
UDPClient.cpp

i=1;
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::Any, 7755);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagram()));

void UDPClient::processPendingDatagram()
{
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;

        datagram.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(datagram.data(),datagram.size());

    ui->lstInfo->addItem(QString::number(i++) + " " +
                             QString::number(datagram.size()));

    }
}

乐活 ...   ...
离线crs811

只看该作者 1楼 发表于: 2014-01-19
ding
乐活 ...   ...
离线crs811

只看该作者 2楼 发表于: 2014-01-19
ding 2
乐活 ...   ...
离线crs811

只看该作者 3楼 发表于: 2014-01-20
ding 3
乐活 ...   ...
离线ashe0817

只看该作者 4楼 发表于: 2014-01-20
传输文件改用TCP协议。
另外,UDP协议发送数据一次不要超过1472字节。

而且,不是说你一次发8KB,接受方就真的能一次收到8KB,存在一个分片问题,这都是你需要处理的。
离线dbzhang800

只看该作者 5楼 发表于: 2014-01-20
qint64 QUdpSocket::writeDatagram(const char * data, qint64 size, const QHostAddress & address, quint16 port)

文档中有这么一句话,不清楚对你有没有影响。

Sending datagrams larger than 512 bytes is in general disadvised, as even if they are sent successfully, they are likely to be fragmented by the IP layer before arriving at their final destination.
离线crs811

只看该作者 6楼 发表于: 2014-01-21
回 4楼(ashe0817) 的帖子
1、我想做类似屏幕共享的效果,是一对多的,需要发广播包
2、我把发送数据改小,比如512B,仍然掉很多包(发300多个,只能收到几十个)

我在网上看到一个帖子,说QT的UDP在windows下发送有问题,不知道是不是这个原因呢?
乐活 ...   ...
离线crs811

只看该作者 7楼 发表于: 2014-01-21
ding 4
乐活 ...   ...
离线dbzhang800

只看该作者 8楼 发表于: 2014-01-21
引用第7楼crs811于2014-01-21 10:23发表的  :
ding 4

不要发这种无意义的回帖!

Qt 出这种严重问题的可能性极低。但如果你真的能在一个简单的小例子中重现这个问题,可以去提交bug
离线crs811

只看该作者 9楼 发表于: 2014-01-21
我也觉得不是QT的原因,但不知道原因啊,我把完整代码发一下,请版主看看

/**************************************************************************************
/*接收方*/
///////////////////////////////////////////////
UDPClient.h

#ifndef UDPCLIENT_H
#define UDPCLIENT_H

#include <QWidget>
#include <QtNetwork>

namespace Ui {
class UDPClient;
}

class UDPClient : public QWidget
{
    Q_OBJECT

public:
    explicit UDPClient(QWidget *parent = 0);
    ~UDPClient();

private:
    Ui::UDPClient *ui;

    QImage *image;
    QUdpSocket *udpSocket;    
    int i;
    QFile file;
    int filesize;
    int filerevsize;

private slots:

    void initSocket();
    void readPendingDatagrams();
};

#endif // UDPCLIENT_H

///////////////////////////////////////////////
UDPClient.cpp

#include "udpclient.h"
#include "ui_udpclient.h"

UDPClient::UDPClient(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::UDPClient)
{
    ui->setupUi(this);

    image = 0;
    i=0;
    filesize=0;

    initSocket();
}

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

/**
* @brief UDPClient::initSocket
*/
void UDPClient::initSocket()
{
    udpSocket = new QUdpSocket(this);
    udpSocket->bind(QHostAddress::Any, 7755);

    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));
}

/**
* @brief UDPClient::readPendingDatagrams
*/
void UDPClient::readPendingDatagrams()
{
    //receive
    while (udpSocket->hasPendingDatagrams())
    {
        //ui->lstInfo->addItem("data coming ... ");

        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;

        udpSocket->readDatagram(datagram.data(), datagram.size(),
            &sender, &senderPort);

        //file size
        if (datagram.startsWith("filesize"))
        {
            ui->lstInfo->addItem("▼ begin rev data");

            filesize = datagram.right(datagram.count()-8).toInt();
            ui->lstInfo->addItem("filesize:"+ QString::number(filesize));

            file.setFileName( "d:/rev.jpg" );

            if (!file.open(QIODevice::WriteOnly | QIODevice::Unbuffered))
                return;

            filerevsize = 0;
            i=1;
        }
        else  //file data
        {
            file.write(datagram.data(),datagram.size());

            filerevsize += datagram.size();

            ui->lstInfo->addItem(QString::number(i) + " rv:" +
                    QString::number(datagram.size()) + " rvd:" +
                    QString::number(filerevsize)+ " all:" +
                    QString::number(filesize));

            //file rev finish
            if (filesize == filerevsize)
            {
                ui->lstInfo->addItem("▲ end rev data");

                image = new QImage("d:/rev.jpg");
                ui->lblImage->setPixmap(QPixmap::fromImage(*image).scaled(ui->lblImage->size()));

                file.close();
                file.remove("d:/rev.jpg");
            }

            qDebug() << i << datagram.size();
        }
    }    

    image = new QImage("d:/rev.jpg");
    ui->lblImage->setPixmap(QPixmap::fromImage(*image).scaled(ui->lblImage->size()));
}

/*发送方*/
///////////////////////////////////////////////
UDPServer.h

#ifndef UDPSERVER_H
#define UDPSERVER_H

#include <QWidget>
#include <QtNetwork>
#include <QDesktopWidget>

namespace Ui {
class UDPServer;
}

class UDPServer : public QWidget
{
    Q_OBJECT

public:
    explicit UDPServer(QWidget *parent = 0);
    ~UDPServer();

private slots:
    void on_btnOpenImage_clicked();

    void shotScreen();
    void sendData();
    void initSocket();

private:
    Ui::UDPServer *ui;    

    QDesktopWidget *desktop;
    QTimer *timer;
    QPixmap pixmap;

    QUdpSocket *udpSocket;
    QFile file;

    int i;
    int loadSize;

};

#endif // UDPSERVER_H

///////////////////////////////////////////////
UDPServer.cpp

#include "udpserver.h"
#include "ui_udpserver.h"

#include <QMainWindow>
#include <QTimer>
#include <QPixmap>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QFileDialog>
#include <QDir>
#include <QDateTime>
#include <QtDebug>
#include <QRect>
#include <QMessageBox>
#include <QPainter>


UDPServer::UDPServer(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::UDPServer)
{
    ui->setupUi(this);

    desktop = QApplication::desktop();

    loadSize = 512; //每次发送数据的大小 :40KB 字节
    i=0;

    initSocket();
}

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

void UDPServer::initSocket()
{
    udpSocket = new QUdpSocket(this);
}

/**
* @brief 截图
*/
void UDPServer::on_btnOpenImage_clicked()
{
    shotScreen();
}

/**
* @brief 截图函数
*/
void UDPServer::shotScreen()
{
    pixmap = QPixmap::grabWindow(desktop->winId());    

    //保存图片:
    pixmap.save("D:/1.jpg", "jpg");
    ui->lblImage->setPixmap(this->pixmap.scaled(ui->lblImage->size()));

    file.setFileName("D:/1.jpg");

    if (!file.open(QIODevice::ReadOnly))
        return;

    ui->txtInfo->setText("file size: " + QString::number(file.size()) + " Byte");

    //send filesize
    ui->lstInfo->addItem("send filesize");
    QByteArray datagram = "filesize"+QString::number(file.size()).toLatin1();
    udpSocket->writeDatagram(  datagram.data(), datagram.size(),
                              QHostAddress::Broadcast, 7755 );

    sendData();
    file.close();
}

/**
* @brief 发送数据
*/
void UDPServer::sendData()
{
    i=0;
    ui->lstInfo->addItem("▼ begin send data");

    //if (!file.atEnd())
    while (!file.atEnd())
    {
        QByteArray line = file.read(loadSize);
        udpSocket->writeDatagram( line , QHostAddress::Broadcast, 7755 );

        i++;
        qDebug() << "send data! " << i << line.size() << file.atEnd();
        ui->lstInfo->addItem(QString::number(i) + " " +
                             QString::number(line.size()));
    }

    ui->lstInfo->addItem("▲ end send data");    
}

乐活 ...   ...
离线crs811

只看该作者 10楼 发表于: 2014-01-21
如图:服务端发送了216个包,客户端接收到了41个包



乐活 ...   ...
离线sinoman

只看该作者 11楼 发表于: 2014-04-27
请问楼主问题解决了吗?我也正在考虑udp丢包问题怎么解决。本身udp丢包是很正常的。
我学习,我快乐
离线退避九舍

只看该作者 12楼 发表于: 2014-04-28
qint64 QUdpSocket::writeDatagram

Warning: Calling this function on a connected UDP socket may result in an error and no packet being sent. If you are using a connected socket, use write() to send datagrams.
离线退避九舍

只看该作者 13楼 发表于: 2014-04-28
你在一个while里不停调用writeDatagram,前面的还没发出去,后面又开始发了
快速回复
限100 字节
 
上一个 下一个