从Qt的图片文件传输来看Qt 中UDP的收发消息writeDatagram和readDatagram

来源:互联网 发布:淘宝众筹能退款吗 编辑:程序博客网 时间:2024/06/03 13:49

        上一篇博客写的是利用Qt的UDP协议传输图片文件。但是有一些问题,比如说还得自己新建一个文件夹存放图片等等。项目想实现的功能是在一个Qt工程的label打开图片文件,另一端就能显示同样的图片,所以加以改进。不需要把接收到的图片写入文件夹中,而是直接把数据都读到picBuffer里面,最后统一显示在label上面。

       过程特别曲折,现在也不敢保证完全明白,还望有明白的高人指点。

       最开始我写的是这样子的:

      发送端:

      

    QString fileName=QFileDialog::getOpenFileName(this,tr("choose image"),".",tr("Images (*.jpg *.png)"));    if(fileName.isEmpty()){        return;    }    QPixmap mPix;    mPix.load(fileName);    ui->picLabel->setPixmap(mPix);    //加载完图片,需要把这张图片传送出去    file.setFileName(fileName);    if(!file.open(QIODevice::ReadOnly)) return;    QByteArray begin ="Begin!";    PicSocket->writeDatagram(begin,localaddr1,10004);//发送begin表示新的图片开始发送了    while(!file.atEnd()){        QByteArray line = file.read(8000);        localaddr1.setAddress("162.105.85.81");        PicSocket->writeDatagram(line,localaddr1,10004);        if(line.size()<8000){            QByteArray yes ="End!";            PicSocket->writeDatagram(yes,localaddr1,10004);        }    }
     每次读8000字节,直到结束,然后分批次发送给指定的地址和端口。文件发送完毕再发送"End!"表示发送彻底结束。

     接收端:

void MainWindow::PicPendingDatagram(){    while(PicSocket->hasPendingDatagrams()){        QByteArray datagram;        datagram.resize(PicSocket->pendingDatagramSize());        QHostAddress sender;        quint16 Pic_port;        PicSocket->readDatagram(datagram.data(),datagram.size(),&sender,&Pic_port);        if(datagram=="Begin!"){            picBuffer.clear();        }        else if(datagram=="End!"){            showPicture();            break;        }        else{            picBuffer.append(datagram);        }    }}void MainWindow::showPicture(){    QBuffer buffer(&picBuffer);    buffer.open(QIODevice::ReadOnly);    QImageReader reader(&buffer);    QImage img =reader.read();  

        接收端如果接受到begin那么久清空上一次的字符串,接着就开始接收,每次都连在picBuffer的后面,直到接收到“End”那么停止接收,跳出循环。

        乍一看没什么不对,但是就是有问题,接收端死活显示不出来图片。于是我做了一些改进,注释掉接收端的break; 这里break是多余的。processPendingDatagram本来就是当端口有数据就会被出发,而hasPendingDatagram是有数据流等待被接收的时候被触发,当发送端发完了没数据了它自动会跳出来,但是还是不行。

void MainWindow::PicPendingDatagram(){    while(PicSocket->hasPendingDatagrams()){        QByteArray datagram;        datagram.resize(PicSocket->pendingDatagramSize());        QHostAddress sender;        quint16 Pic_port;        PicSocket->readDatagram(datagram.data(),datagram.size(),&sender,&Pic_port);        if(datagram=="Begin!"){            picBuffer.clear();        }        else if(datagram=="End!"){            showPicture();            //break; //注释掉了还是不行。        }        else{            picBuffer.append(datagram);        }    }}

        那到底怎么回事?

        我把接收端得到的数据的长度打印出来,这时候发现了一些问题。按理来说应该是一些8000后面接一个小于8000的数字,但是实际上输出只有一堆8000,少了最后的一些数据,输出后面接着一句话:Corrupt JPEG data: premature end of data segment.  这是什么意思? 为什么少了很多的数据呢?后面的数据去哪里了?

        我猜想是接收的时候,如果发送数据比较快,接收的时候本来一直在hasPendingDatagram()里面循环,但是假设遇到网络问题,突然有一个包有延迟,接收慢了,那么会重新从picPendingDatagram出发,而不是一直在里层循环,这样造成了数据崩溃。因为接收的时候输出有时候能输出3个8000有时候是4个,是变化的,所以我猜测和网络状态有关系。从UDP的触发机制来看,如果有一个包慢了,可能就重新从picPendingDatagram开始写入了,造成错误。

        所以我想的是,那么从发送的时候开始,我慢一些,每次都让他在picPendingDatagram触发,而不是从里层的有数据流堆积开始触发,这样数据也不会乱。成功了。在一个端的label控件加载出来的图片,也能显示在另一个端的label上面了。代码如下:

void MainWindow::on_pushButton_clicked(){    QString fileName=QFileDialog::getOpenFileName(this,tr("choose image"),".",tr("Images (*.jpg *.png)"));    if(fileName.isEmpty()){        return;    }    QPixmap mPix;    mPix.load(fileName);    ui->picLabel->setPixmap(mPix);    //加载完图片,需要把这张图片传送出去    file.setFileName(fileName);    if(!file.open(QIODevice::ReadOnly)) return;    QByteArray begin ="Begin!";    PicSocket->writeDatagram(begin,localaddr1,10004);    while(!file.atEnd()){        QByteArray line = file.read(8000);        localaddr1.setAddress("162.105.85.81");        PicSocket->writeDatagram(line,localaddr1,10004);        _sleep(50);//延迟50ms        if(line.size()<8000){            QByteArray yes ="End!";            PicSocket->writeDatagram(yes,localaddr1,10004);            qDebug()<<"End!"<<endl;        }}
        我设置每次延迟的参数是50ms,这样每次接收都会认为是从picPendingDatagram开始接收,因为两个包的数据间隔足够长,不会造成数据错乱了。

        对于文件这种东西,最好还是用TCP,像UDP这种无确认的,丢包什么的会很难受,图片的话丢了一个包就全显示不出来了。。以及我还是不是很清楚究竟为什么这么做能成功,上面的只是我的猜想。希望各位能提出自己的看法,共同讨论,希望大家不吝赐教啊。。

      

阅读全文
1 0