QT的TCP应用-传输图片

1.server.h

#ifndef SERVER_H
#define SERVER_H

#include <QMainWindow>
#include<QLabel>
#include<QtNetwork/QHostInfo>
#include<QtNetwork/QTcpServer>
#include<QtNetwork/QTcpSocket>
#include<QFile>

namespace Ui {
class Server;
}

class Server : public QMainWindow
{
    Q_OBJECT
private:
    QLabel *LabListen;
    QLabel *LabSocketState;
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;
    QString getlocalIP();
private:  //file
    QTcpServer *fileServer;
    QTcpSocket *fileSocket;
    qint64 totalBytes;
    qint64 bytesReceived;
    qint64 bytestoWrite;
    qint64 bytesWritten;
    qint64 filenameSize;
    QString filename;
    QString m_imgDirPath;
    ///每次发送数据大小
    qint64 perDataSize;
    QFile *localFile;
    本地缓冲区
    QByteArray inBlock;
    QByteArray outBlock;

    void initSocket();
    void initFileSocket();

private slots:
    void onNewConnection();
    void onSocketStateChange(QAbstractSocket::SocketState socketState);
    void onClientConnected();
    void onClientDisconnected();
    void onSocketReadyRead();

    void acceptFileConnection();
    void updateFileProgress();
    void displayError(QAbstractSocket::SocketError socketError);
    void updateFileProgress(qint64);

    //void on_openImgButton_clicked(); //浏览按钮-点击槽函数
    void on_imgListWidget_clicked(const QModelIndex &index);  //图片列表-点击槽函数

protected:
    void closeEvent(QCloseEvent *event);

private slots:
   void on_acHostInfo_triggered();
   void on_actStart_triggered();
   void on_actStop_triggered();
   void on_btnSendMsg_clicked();
   void on_btnSaveDir_clicked();
   void on_btnSelectFile_clicked();
   void on_btnSendFile_clicked();
   void Auto_get_mac_IP();
   void on_choose_image_pushButton_clicked();

   void on_closeimage_pushButton_clicked();

   void on_actClear_triggered();

public:
    explicit Server(QWidget *parent = 0);
    ~Server();
   //QMediaPlayer *player1,*player2;

private:
    Ui::Server *ui;
};

#endif // SERVER_H

2、main.c

#include "server.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Server w;
    w.show();

    return a.exec();
}

3、server.cpp

#include "server.h"
#include "ui_server.h"
#include<QFileDialog>
#include <QMessageBox>
#include <QMainWindow>
#include <QMovie>
#include <QDebug>
#include <QDateTime>
#include <QSettings>
#include <qnetworkinterface.h>

QString Server::getlocalIP()
{
    QString hostName=QHostInfo::localHostName();
    QHostInfo hostInfo=QHostInfo::fromName(hostName);

    QList<QHostAddress> addList=hostInfo.addresses();
    if(!addList.isEmpty())
        for(int i=0;i<addList.count();i++)
        {
            QHostAddress localIP =addList.at(i);
            if(localIP.protocol()==QAbstractSocket::IPv4Protocol)
                return localIP.toString();
        }
    return "";
}

Server::Server(QWidget *parent) :QMainWindow(parent), ui(new Ui::Server)
{
    ui->setupUi(this);
    this->setWindowTitle("Tcp Server");
    initSocket();
    initFileSocket();
    Auto_get_mac_IP();
    //设置指定背景色
    ui->image_label->setStyleSheet("background-color:rgb(222, 222, 222);");//图片显示区域颜色
    ui->imgListWidget->setStyleSheet("background-color:rgb(222, 222, 222);");//接收名字区域设置
    ui->plainTextEdit->setStyleSheet("background-color:rgb(222, 222, 222);");//信息显示区域背景颜色

    ui->fg_label->setStyleSheet("QLabel{background-color:rgb(143, 0, 0);}");//信息提示去颜色
    ui->fg_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");

    ui->img_label->setStyleSheet("QLabel{background-color:rgb(143, 0, 0);}");//信息提示去颜色
    ui->img_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");

    ui->information_prompt_area_laber->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");
    ui->Picture_display_area_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");//图片显示区域背景颜色
}
void Server::Auto_get_mac_IP()//放到自动程序中,开机获取本机地址
{

//通过QNetworkInterface类来获取本机的IP地址和网络接口信息。
 QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();//获取所有网络接口的列表
  //获取所有网络接口的列表
 foreach(QNetworkInterface interface,list)
    {  //遍历每一个网络接口
     qDebug() << "Device: "<<interface.name();  //设备名
     //硬件地址
     qDebug() << "HardwareAddress: "<<interface.hardwareAddress();

/**********************************************************************************************/
/*
 * ubuntu下获取ip地址  start
 */
/**********************************************************************************************/
if(interface.name()=="enp2s0"|interface.name()=="ethernet_32774")//我的ubuntu端口是enp2s0,windosethernet_32774 是你的需要根据自己的来判断
    {
   QList<QNetworkAddressEntry> entryList = interface.addressEntries();
          //获取IP地址条目列表,每个条目中包含一个IP地址,一个子网掩码和一个广播地址
     foreach(QNetworkAddressEntry entry,entryList)
      {//遍历每一个IP地址条目

        if( entry.ip().toString().size() < 16)//区分IPV6和IPV4
       {
        qDebug()<<"IP Address: "<<entry.ip().toString();
                    //IP地址
        qDebug()<<"Netmask: "  <<entry.netmask().toString();
                    //子网掩码
        qDebug()<<"Broadcast: "<<entry.broadcast().toString();
                    //广播地址
        ui->editIP->clear();//
        ui->editIP->setText(QString (entry.ip().toString()));
        }
       }
    }
/**********************************************************************************************/
/*
* ubuntu下获取ip地址  end
*/
/**********************************************************************************************/
 }
}
void Server::on_acHostInfo_triggered()
{
   Auto_get_mac_IP();//按键 再次刷新ip地址
}

void Server::initSocket()
{
    LabListen=new QLabel("监听状态:");
    LabListen->setMinimumWidth(150);
    ui->statusBar->addWidget(LabListen);
    LabSocketState=new QLabel("Socket状态:");//
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}

void Server::initFileSocket()
{

     文件传送相关变量初始化
    perDataSize = 64*1024;
    totalBytes = 0;
    bytestoWrite = 0;
    bytesWritten = 0;
    bytesReceived = 0;
    filenameSize = 0;
    ///文件传送套接字
    fileSocket = new QTcpSocket(this);
    fileServer = new QTcpServer(this);

    quint16 port=ui->spinPort->value()+1;//端口
    qDebug()<<"initFileSocket"<<port;

    fileServer->listen(QHostAddress::Any,ui->spinPort->value()+1);
    connect(fileServer,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));

}
Server::~Server()
{
    delete ui;
    delete tcpServer;
    delete fileServer;
}

void Server::on_actStart_triggered()
{
    //从界面上读取ip和端口
    const QString address_IP=ui->editIP->text();//IP地址
          quint16 port=ui->spinPort->value();//端口
   //可以使用 QHostAddress::Any 监听所有地址的对应端口
    const QHostAddress address=(address_IP=="Any")?QHostAddress::Any:QHostAddress(address_IP);
    tcpServer->listen(address,port);//

    tcpServer->listen(QHostAddress::LocalHost,port);
    ui->plainTextEdit->appendPlainText("**开始监听...");
    ui->plainTextEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));
    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);
    LabListen->setText("监听状态:正在监听");
}
void Server::on_actStop_triggered()
{//停止监听
    if (tcpServer->isListening()) //tcpServer正在监听
    {
        tcpServer->close();//停止监听
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        LabListen->setText("监听状态:已停止监听");
    }
}

void Server::onNewConnection()
{
    ui->plainTextEdit->appendPlainText("有新连接");
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket
    connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));//
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpSocket->state());

    //连接信号与槽
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

     qDebug()<<"Client connected success.";
}
void Server::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;
    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void Server::onClientConnected()
{//客户端接入时
    ui->plainTextEdit->appendPlainText("**client socket connected");
    ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort()));
}

void Server::onClientDisconnected()
{//客户端断开连接时
    ui->plainTextEdit->appendPlainText("**client socket disconnected");
    tcpSocket->deleteLater();
   // deleteLater();
}

void Server::onSocketReadyRead()
{
    ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readAll());

//    ui->image_label->setPixmap(QPixmap(QString::fromLocal8Bit("E:\QT\TCP_Client_Server\\1.png"))); // 在imgLabel标签上显示图片
//    ui->image_label->setScaledContents(true);
//    ui->image_label->show();
}

void Server::on_btnSendMsg_clicked()
{
    QString  msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray  str=msg.toUtf8();
    //str.append('\n');//添加一个换行符
    tcpSocket->write(str);
}

void Server::closeEvent(QCloseEvent *event)
{//关闭窗口时停止监听
    if (tcpServer->isListening())
        tcpServer->close();//停止网络监听
    if (fileServer->isListening())
        fileServer->close();//停止网络监听
    event->accept();
}

void Server::acceptFileConnection()
{

    bytesWritten = 0;
    ///每次发送数据大小为64kb
    perDataSize = 64*1024;
    fileSocket =fileServer->nextPendingConnection();
    ///接受文件
    readyRead()当网络套接字上有新的网络数据有效负载时
    connect(fileSocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));
    connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));

     处理异常
    connect(fileSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));

}

/**
 * 接收文件进度
 * @brief Server::updateFileProgress
 */
void Server::updateFileProgress()
{
    QDataStream inFile(fileSocket);
    inFile.setVersion(QDataStream::Qt_5_6);
    ui->plainTextEdit->appendPlainText("updateFileProgress");

    ///如果接收到的数据小于16个字节,保存到来的文件头结构
    if(bytesReceived <= sizeof(qint64)*2)
    {

        QByteArray bytes = NULL;
        while(this->fileSocket->waitForReadyRead(100))
        {
            qDebug()<<"Data receiving...";
            bytes.append(this->fileSocket->readAll());
        }

        //Send Back Data to Client
         if(this->fileSocket->isWritable())
         {
                //结尾中的'\n'表示数据发送完毕
//                QString sendData = "ok\n" ;
//                QByteArray  strs=sendData.toUtf8();
//                this->fileSocket->write(strs);
          }
          else
          {
              qDebug()<<"Cannot send back data to Client.";
          }


        QPixmap pixmap;
        pixmap.loadFromData(bytes);
        //显示到GUI中
        int with = ui->image_label->width();
        int height = ui->image_label->height();

        //QPixmap fitpixmap = pixmap.scaled(with, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);  // 饱满填充
         QPixmap fitpixmap = pixmap.scaled(with, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);  // 按比例缩放
         //ui->image_label->setScaledContents(false);    //根据label大小缩放图片
        ui->image_label->setPixmap(fitpixmap);

        //时间保存文件名
        QDateTime datetime;
        QString timestr = datetime.currentDateTime().toString("yyyyMMddHHmmss");

        //保存路径
         filename =  ui->editSaveDir->text()+"/"+timestr+".png";
         qDebug()<<"filename"<<filename;
         localFile = new QFile(filename);
         if(!localFile->open(QFile::WriteOnly))
         {
             ui->plainTextEdit->appendPlainText("Server::open file error!");
             return;
         }

         //保存文件
         localFile->write(bytes);
         bytes.resize(0);
    }
    ///如果接收到的数据小于16个字节,保存到来的文件头结构
    if(bytesReceived <= sizeof(qint64)*2)
    {

        if((fileSocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
        {
             接收数据总大小信息和文件名大小信息
            inFile>>totalBytes>>filenameSize;
            bytesReceived += sizeof(qint64)*2;
            qDebug()<<"filenameSize success."<< filenameSize;
        }
        if((fileSocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
        {
            inFile>>filename;
            bytesReceived += filenameSize;
            接收的文件放在指定目录下
            filename = ui->editSaveDir->text()+"/"+filename;
            localFile = new QFile(filename);
            if(!localFile->open(QFile::WriteOnly))
            {
                ui->plainTextEdit->appendPlainText("Server::open file error!");
                return;
            }
        }
        else
            return;
    }
    /如果接收的数据小于总数据,则写入文件
    if(bytesReceived < totalBytes)
    {
        bytesReceived += fileSocket->bytesAvailable();
        inBlock = fileSocket->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    更新进度条显示
    this->ui->progressBarRec->setMaximum(totalBytes);
    this->ui->progressBarRec->setValue(bytesReceived);
    数据接收完成时
    if(bytesReceived == totalBytes)
    {
        this->ui->plainTextEdit->appendPlainText("Receive file successfully!");
        bytesReceived = 0;
        totalBytes = 0;
        filenameSize = 0;
        localFile->close();
        //fileSocket->close();
    }
}
void Server::updateFileProgress(qint64 numBytes)
{ 已经发送的数据大小
    bytesWritten += (int)numBytes;
    如果已经发送了数据
    if(bytestoWrite > 0)
    {
        outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
        ///发送完一次数据后还剩余数据的大小
        bytestoWrite -= ((int)fileSocket->write(outBlock));
        ///清空发送缓冲区
        outBlock.resize(0);
    }
    else
        localFile->close();
    更新进度条
    this->ui->progressBarSend->setMaximum(totalBytes);
    this->ui->progressBarSend->setValue(bytesWritten);

    如果发送完毕
    qDebug()<<"bytesWritten"<<bytesWritten<<"--"<<"totalBytes"<<totalBytes;
    if(bytesWritten == totalBytes)
    {
       bytesWritten=0;totalBytes=0;
       localFile->close();
      // fileSocket->close();
       qDebug()<<ui->progressBarRec->value()<<"value";
       qDebug()<<ui->progressBarRec->maximum()<<"maximum";
    }
}
/**
 * @brief Server::getImage base64 转图片
 * @param data
 * @return
 */
//QImage Server::getImage(const QString &data)
//{
//    QByteArray imageData = QByteArray::fromBase64(data.toLatin1());
//    QImage image;
//    image.loadFromData(imageData);
//    return image;
//}

void Server::displayError(QAbstractSocket::SocketError socketError)
{
    ui->plainTextEdit->appendPlainText(fileSocket->errorString());
    //socket->close();
}

void Server::on_btnSaveDir_clicked()
{
    ui->editSaveDir->setText(QFileDialog::getExistingDirectory(this,"请选择保存路径"));
}
void Server::on_btnSelectFile_clicked()
{
   //  ui->editFile->setText(QFileDialog::getOpenFileName(this,"请选择待发送文件"));
    //???fileSocket->open(QIODevice::WriteOnly);
    ///文件传送进度更新
    //connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
    filename = QFileDialog::getOpenFileName(this,"Open a file");
    ui->editFile->setText(filename);
}

void Server::on_btnSendFile_clicked()
{

    localFile = new QFile(filename);
    if(!localFile->open(QFile::ReadOnly))
    {
        ui->plainTextEdit->appendPlainText("Client:open file error!");
        return;
    }
    ///获取文件大小
    this->totalBytes = localFile->size();
    QDataStream sendout(&outBlock,QIODevice::WriteOnly);
    sendout.setVersion(QDataStream::Qt_4_8);
    QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);

    qDebug()<<sizeof(currentFileName);
    保留总代大小信息空间、文件名大小信息空间、文件名
    sendout<<qint64(0)<<qint64(0)<<currentFileName;
    totalBytes += outBlock.size();
    sendout.device()->seek(0);
    sendout<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));

    bytestoWrite = totalBytes-fileSocket->write(outBlock);
    outBlock.resize(0);
}
/*
void MainWindow::on_openImgButton_clicked()
{
    //m_imgDirPath = QFileDialog::getExistingDirectory(this); // 获取图片所在目录的具体路径
    m_imgDirPath=ui->lineEdit->text();
    QDir dir(m_imgDirPath);

    QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files); // 获取目录下的文件

    QString filePath; // 保存图片图片的绝对路径
    // 在QListWidget中列出目录下的文件
    for(int i=0; i<fileInfoList.count(); i++)
    {
        filePath.clear(); //清除上一次图片路径内容
        filePath.append(m_imgDirPath + "/" + fileInfoList.at(i).fileName()); // 获得图片文件的绝对路径

        if(fileInfoList.at(i).fileName() == "." || fileInfoList.at(i).fileName() == "..") // 跳过这两个隐藏目录
        {
            continue;
        }
        QListWidgetItem *item = new QListWidgetItem(QIcon(filePath), fileInfoList.at(i).fileName()); // 建立图片缩小图标
        ui->imgListWidget->addItem(item); // 把图片缩小图标和名称显示在列表窗口中
    }
}


*/
void Server::on_choose_image_pushButton_clicked()
{
 /*   QString filename;
    QPixmap image_label;
    filename=QFileDialog::getOpenFileName(this,tr("选择图像"),"",tr("Images (*.png *.bmp *.jpg *.tif *.GIF )"));//可打开的文件类型
    if(!filename.isEmpty())
    {
        QImage image(filename);
        ui->image_label->setPixmap(image_label.fromImage(image));// ui->image_label就是label的控件名字
        ui->image_label->setScaledContents(true);
        ui->image_label->show();

    }
*/

    m_imgDirPath=ui->editSaveDir->text();
    QString filter;
    QDir dir(m_imgDirPath);
    QFileInfoList fileInfoList = dir.entryInfoList(); // 获取目录下的文件
    QString filePath; // 保存图片图片的绝对路径
    foreach(QFileInfo fileinfo, fileInfoList )filter = fileinfo.suffix(); //后缀名
    // 在QListWidget中列出目录下的文件


    for(int i=0; i<fileInfoList.count(); i++)
    {
        filePath.clear(); //清除上一次图片路径内容
        filePath.append(m_imgDirPath + "/" + fileInfoList.at(i).fileName()); // 获得图片文件的绝对路径
      if(fileInfoList.at(i).fileName() == "." || fileInfoList.at(i).fileName() == "..") // 跳过这两个隐藏目录
        {
            continue;
        }
        QListWidgetItem *item = new QListWidgetItem(QIcon(filePath), fileInfoList.at(i).fileName()); // 建立图片缩小图标
        ui->imgListWidget->addItem(item); // 把图片缩小图标和名称显示在列表窗口中
    }
        ui->img_label->setText("图片加载完成");
}
//图片列表-点击槽函数
void Server::on_imgListWidget_clicked(const QModelIndex &index)
{
    Q_UNUSED(index);

    QString imgPath = (m_imgDirPath + "/" + ui->imgListWidget->currentItem()->text());

    if(imgPath.endsWith(".gif") || imgPath.endsWith(".Gif")) //判断是否是gif动图
    {

        QMovie *movie =new QMovie(imgPath);
        ui->image_label->setMovie(movie);
        movie->start();
    }
    else
    {
        //显示图片
        int with = ui->image_label->width();
        int height = ui->image_label->height();

        //QPixmap fitpixmap = pixmap.scaled(with, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);  // 饱满填充
         QPixmap fitpixmap = QPixmap(imgPath).scaled(with, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);  // 按比例缩放
         //ui->image_label->setScaledContents(false);    //根据label大小缩放图片
        ui->image_label->setPixmap(fitpixmap);

      // ui->image_label->setPixmap(QPixmap(imgPath)); // 在imgLabel标签上显示图片
    //   ui->image_label->setScaledContents(true);    //根据label大小缩放图片
    }

}
void Server::on_closeimage_pushButton_clicked()
{
    ui->image_label->clear();
    ui->imgListWidget->clear();
    ui->img_label->setText("请加载图片");
}

void Server::on_actClear_triggered()
{
   ui->plainTextEdit->clear();
}

实际效果:
在这里插入图片描述
下载:https://gitee.com/pang_xi_wen/qtq.git

评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

那肯定是很多年以后!

你的鼓励就我最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值