QT之UDP图片传输

上一篇博客是实现了UDP实现文本传输,而这一篇是实现图片传输。代码的话,是在文本传输的例子上进行修改的。

从本质上来说,无论是传输文本,还是传输图片,在传输的过程中实际上都是传输的二进制数据,只不过是它们的表现形式不一样罢了。对于文本而已,就是单纯的ASCII码(也就是一个字节的16进制数),而对于图片这种类型的文件,我们也是可以先进行数据转换,然后将转换后的数据发送到另外一个客户端,另外一个客户端接收到数据,再将其转换为图片的形式显示出来。其实这里面就只是涉及到一个编码和转码的问题而已。知道原理是什么之后,接下来就是用代码去怎么去实现这个编码和转码的事了。

做过图片转换的童鞋来说,对图片base64编码肯定不陌生。网上也提供了很多这样的工具,就是打开一张图片,然后转换为ASCII码的数据,感兴趣的童鞋可以去了解看看。在QT中,也是提供了base64编码的方法供我们使用的,现在就来看看代码怎么实现吧。

UI图如下,主要是在上一个工程简单修改而来的【说实话,确实是丑,但这里不是关键地方哈~~~~】。

相比上一工程,主要增加了4个控件,分别为两个label和两个按键。

核心代码(即编码和转码)如下:

1.将图片数据转换成base64格式

QByteArray MainWindow::get_imagedata_from_imagefile(const QImage &image)
{
    QByteArray imageData;
    QBuffer buffer(&imageData);
    image.save(&buffer, "jpg");
    imageData = imageData.toBase64();
    return imageData;
}

2.将base64数据转换为图片

QImage MainWindow::get_imagedata_from_byte(const QString &data)
{
    QByteArray imageData = QByteArray::fromBase64(data.toLatin1());
    QImage image;
    image.loadFromData(imageData);
    return image;
}

相对于上一个版本主要有以下修改:

1.在mainwindow.h文件中增加以下代码

#include <QImage>//增加头文件



//在类中增加以下变量定义和函数声明
QString image_file_data;
QImage image;
QString picture_data;
QByteArray get_imagedata_from_imagefile(const QImage &image);
QImage get_imagedata_from_byte(const QString &data);

2.修改原来的void MainWindow::udp_server_receive_data()函数

//将原来的文字传输改成图片数据转码
void MainWindow::udp_server_receive_data()
{
    QByteArray datagram;
    while( udp_server->hasPendingDatagrams())
    {
        //数据不为空
        datagram.resize( udp_server->pendingDatagramSize() );
        //接收数据报
        udp_server->readDatagram(datagram.data(),datagram.size(), &client_address, &client_port);
        /* 文本传输注销
        //label->setText(datagram);
        QString ip_addr_temp =  client_address.toString();//"::ffff:192.168.124.11"
        QString ip_addr;
        int i = 0;
        //填充ip地址
        for(i = 7; ip_addr_temp[i] != '\0'; i ++ )
        {
            ip_addr[i-7] = ip_addr_temp[i];
        }



        //<receive ip:port>:data
        receive_buff += QString("<receive ") + ip_addr + QString(":") + QString::number(client_port) +  QString(">:") + datagram.data();
        //显示区
        ui->receive_buff_textBrowser->setText(receive_buff);
        */
        //接收显示的图片
        QImage image_temp = get_imagedata_from_byte(datagram.data());
        ui->image_label_2->setPixmap(QPixmap::fromImage(image_temp).scaled(ui->image_label_2->size()));

    }
}

3.修改发送函数,这里的话是使用了发送图片的控件槽发送的。跟之前使用发送文本的控件槽函数差不多,就是多了一个编码的过程

void MainWindow::on_send_picture_pushButton_clicked()
{
    //获取要发送的客户端ip和端口号
    image_file_data = get_imagedata_from_imagefile(image);//获取图片数据
    qDebug()<<"===========size==================="<<image_file_data.size();

    QString client_addr_buff = ui->udp_client_ip_textEdit->document()->toPlainText();
    QString client_port_buff = ui->udp_client_port_textEdit->document()->toPlainText();
    //发送图片
    udp_server->writeDatagram(image_file_data.toLatin1(),image_file_data.size(),QHostAddress(client_addr_buff),client_port_buff.toInt());
}

对比前面一个文本发送的程序,就是改了上述三个关键的函数发送和接收地方。对于还有一些其他的小细节问题,比如打开文件之类的,就请看完整程序吧。

完整代码如下:

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <QUdpSocket>

#include <QImage>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void localhost_ip_get(void);

    QUdpSocket *udp_server;
    QString  receive_buff;
    QHostAddress client_address;
    quint16 client_port = 0;

    //图片显示新增
    QString image_file_data;
    QImage image;
    QString picture_data;
    QByteArray get_imagedata_from_imagefile(const QImage &image);
    QImage get_imagedata_from_byte(const QString &data);
    
private:
    Ui::MainWindow *ui;

private slots:
    void udp_server_receive_data(void);
    void on_listen_pushButton_clicked();
    void on_send_pushButton_clicked();
    void on_clear_send_buff_pushButton_clicked();
    void on_clear_receive_buff_pushButton_clicked();

    void on_open_picture_pushButton_clicked();
    void on_send_picture_pushButton_clicked();
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QNetworkInterface>
#include <QMessageBox>
#include <QFileDialog>
#include <QBuffer>


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    //设置标题
    this->setWindowTitle("UDP_SERVER");

    localhost_ip_get();
}

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

void MainWindow::localhost_ip_get()
{
    udp_server = new QUdpSocket(this);
    ui->udp_server_ip_textEdit->setText(QNetworkInterface().allAddresses().at(1).toString());//获取本地IP
}

void MainWindow::udp_server_receive_data()
{
    QByteArray datagram;
    while( udp_server->hasPendingDatagrams())
    {
        //数据不为空
        datagram.resize( udp_server->pendingDatagramSize() );
        //接收数据报
        udp_server->readDatagram(datagram.data(),datagram.size(), &client_address, &client_port);
        /*
        //label->setText(datagram);
        QString ip_addr_temp =  client_address.toString();//"::ffff:192.168.124.11"
        QString ip_addr;
        int i = 0;
        //填充ip地址
        for(i = 7; ip_addr_temp[i] != '\0'; i ++ )
        {
            ip_addr[i-7] = ip_addr_temp[i];
        }



        //<receive ip:port>:data
        receive_buff += QString("<receive ") + ip_addr + QString(":") + QString::number(client_port) +  QString(">:") + datagram.data();
        //显示区
        ui->receive_buff_textBrowser->setText(receive_buff);
        */
        //接收显示的图片
        QImage image_temp = get_imagedata_from_byte(datagram.data());
        ui->image_label_2->setPixmap(QPixmap::fromImage(image_temp).scaled(ui->image_label_2->size()));

    }
}

void MainWindow::on_listen_pushButton_clicked()
{
    //readyRead:每当有数据报来时发送这个信号
    if(ui->listen_pushButton->text() == "监听")
    {
        ui->listen_pushButton->setText("断开");
        //获取端口号
        QString port_buff = ui->udp_server_port_textEdit->document()->toPlainText();
        quint16 port_val = (quint16 )port_buff.toInt();
        udp_server->bind(port_val,QUdpSocket::ShareAddress);
        connect(udp_server,SIGNAL(readyRead()),this,SLOT(udp_server_receive_data()));
    }
    else
    {
        ui->listen_pushButton->setText("监听");
        udp_server->close();
    }
}

void MainWindow::on_send_pushButton_clicked()
{
    //获取填写的数据
    QString send_buff = ui->send_buff_textEdit->document()->toPlainText();
    //获取要发送的客户端ip和端口号
    QString client_addr_buff = ui->udp_client_ip_textEdit->document()->toPlainText();
    QString client_port_buff = ui->udp_client_port_textEdit->document()->toPlainText();
    if(client_addr_buff == "" || client_port_buff == "")
    {
        QMessageBox::information(nullptr, "Error", "IP或端口号内容不能为空");
        return;
    }
    if(send_buff == "")
    {
         QMessageBox::information(nullptr, "Error", "内容不能为空");
         return;
    }
    //udp_server->writeDatagram(send_buff.toLatin1(),send_buff.size(),client_address,client_port);
    udp_server->writeDatagram(send_buff.toLatin1(),send_buff.size(),QHostAddress(client_addr_buff),client_port_buff.toInt());
}

void MainWindow::on_clear_send_buff_pushButton_clicked()
{
    ui->send_buff_textEdit->clear();
}

void MainWindow::on_clear_receive_buff_pushButton_clicked()
{
    ui->receive_buff_textBrowser->clear();
}


void MainWindow::on_open_picture_pushButton_clicked()
{
    QString file_name = QFileDialog::getOpenFileName(this,"open file",QDir::currentPath(),"Image Files(*.jpg *.png)");
    if(file_name == "")
    {
        return;
    }

    image.load(file_name);
    ui->image_label->setPixmap(QPixmap::fromImage(image).scaled(ui->image_label->size()));//显示发送的图片
    //ui->image_label
}

QByteArray MainWindow::get_imagedata_from_imagefile(const QImage &image)
{
    QByteArray imageData;
    QBuffer buffer(&imageData);
    image.save(&buffer, "jpg");
    imageData = imageData.toBase64();
    return imageData;
}

QImage MainWindow::get_imagedata_from_byte(const QString &data)
{
    QByteArray imageData = QByteArray::fromBase64(data.toLatin1());
    QImage image;
    image.loadFromData(imageData);
    return image;
}

void MainWindow::on_send_picture_pushButton_clicked()
{
    //获取要发送的客户端ip和端口号
    image_file_data = get_imagedata_from_imagefile(image);//获取图片数据
    qDebug()<<"===========size==================="<<image_file_data.size();

    QString client_addr_buff = ui->udp_client_ip_textEdit->document()->toPlainText();
    QString client_port_buff = ui->udp_client_port_textEdit->document()->toPlainText();
    //发送图片
    udp_server->writeDatagram(image_file_data.toLatin1(),image_file_data.size(),QHostAddress(client_addr_buff),client_port_buff.toInt());
}

测试结果:(测试图片不能大于80k,否则不能正常显示

第一种:自发自收

1.运行程序,点击监听,然后服务器IP和端口号拷贝到客户端IP和PORT。

2.打开一张图片,然后点击发送图片。

第二种方法:服务器只负责收,图片数据是别的客户端发送过来的。【主要是让童鞋们更加了解这个编码和转码的过程】

1.这里的话,我们需要将图片转码,图片转码工具。我们打开一张图片,然后转换得到base64编码的内容(注意前面这部分的数据不要),然后将拷贝数据到一个UDP客户端,通过UDP客户端进行发送数据给这里的服务器进行显示。

2.重新运行一次程序,点击监听。然后打开另外一个UDP工具的工具,点击链接QT的服务器,然后将图片数据拷贝发送,这样我们就可以在QT上位机上看到我们的图片了。

方法1和方法2的区别:

方法1是QT上位机里面自己做了转码和编码的工作。而方法2则是将编码的工作丢给了外面,只做转码的部分(只做数据接收)。

如果这篇文章,对你有帮助,就点个赞再走吧~~~~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值