QT项目二:局域网聊天工具

news/2024/4/19 18:35:23/文章来源:https://www.cnblogs.com/managechina/p/16635127.html
QT项目二:局域网聊天工具
参考《Qt及Qt Quick开发实战精解》,该书介绍的很详细,不做过多介绍。

末尾有源码下载地址

1.main.cpp
#include "widget.h"
 
#include <QApplication>
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Widget w;
    w.show();
    return a.exec();
}
2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
#include <QTextCharFormat>
 
class QUdpSocket;
class TcpServer;
 
 
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
 
//枚举变量信息类型:消息、新用户加入、用户退出、文件名、拒绝接收文件
enum MessageType
{
    Message,
    NewParticipant,
    ParticipantLeft,
    FileName,
    Refuse
};
 
class Widget : public QWidget
{
    Q_OBJECT
 
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
 
protected:
    void newParticipant(QString userName, QString localHostName, QString ipAddress);
    void participantLeft(QString userName, QString localHostName, QString time);
    void sendMessage(MessageType type, QString serverAddress="");
 
    void closeEvent(QCloseEvent *event);
 
    QString getIp();
    QString getUserName();
    QString getMessage();
 
    bool saveFile(const QString &fileName);
 
    void hasPendingFile(QString userName, QString serverAddress,
                        QString clientAddress, QString fileName);
private:
    Ui::Widget *ui;
    QUdpSocket *udpSocket;
    quint16 port;
 
    QString fileName;
    TcpServer *server;
    QColor color;
 
private slots:
    void processPendingDatagrams();
    void on_sendButton_clicked();
    void getFileName(QString name);
    void on_sendToolBtn_clicked();
    void on_fontComboBox_currentFontChanged(const QFont &f);
    void on_sizeComboBox_currentIndexChanged(const QString &arg1);
    void on_boldToolBtn_clicked(bool checked);
    void on_italicToolBtn_clicked(bool checked);
    void on_underlineToolBtn_clicked(bool checked);
    void on_colorToolBtn_clicked();
    void currentFormatChanged(const QTextCharFormat &format);
    void on_saveToolBtn_clicked();
    void on_clearToolBtn_clicked();
    void on_exitButton_clicked();
};
#endif // WIDGET_H
3.widget.cpp
#include <QUdpSocket>
#include <QHostInfo>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QNetworkInterface>
#include <QProcess>
#include <QDebug>
#include <QFileDialog>
#include <QColorDialog>
#include <QThread>
#include "widget.h"
#include "ui_widget.h"
#include "tcpserver.h"
#include "tcpclient.h"
 
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
 
    //UDP socket, 用于对话聊天
    udpSocket = new QUdpSocket(this);
    port = 45454;
    udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
    connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
    sendMessage(NewParticipant);
 
    //TCP socket, 用于文件传输
    server = new TcpServer(this);
    connect(server, SIGNAL(sendFileName(QString)), this, SLOT(getFileName(QString)));
 
    //字体格式自动切换显示
    connect(ui ->messageTextEdit, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
            this, SLOT(currentFormatChanged(const QTextCharFormat)));
}
 
Widget::~Widget()
{
    delete ui;
}
 
void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
{
    bool isEmpty = ui ->userTableWidget
            ->findItems(localHostName, Qt::MatchExactly).isEmpty();
 
    qDebug("%s:%d, userName = %s, localHostName = %s, ipAddress = %s", __FUNCTION__, __LINE__,
           qPrintable(userName), qPrintable(localHostName), qPrintable(ipAddress));
    if(isEmpty)
    {
        QTableWidgetItem *user = new QTableWidgetItem(userName);
        QTableWidgetItem *host = new QTableWidgetItem(localHostName);
        QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
 
        ui ->userTableWidget ->insertRow(0);
        ui ->userTableWidget ->setItem(0, 0, user);
        ui ->userTableWidget ->setItem(0, 1, host);
        ui ->userTableWidget ->setItem(0, 2, ip);
 
        ui ->messageBrower ->setTextColor(Qt::gray);
        ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
        ui ->messageBrower ->append(tr("%1 在线!").arg(userName));
 
        ui ->userNumLabel ->setText(tr("在线人数:%1")
                                    .arg(ui ->userTableWidget ->rowCount()));
 
        sendMessage(NewParticipant);
    }
 
}
 
void Widget::participantLeft(QString userName, QString localHostName, QString time)
{
    int rowNum = ui ->userTableWidget ->findItems(localHostName,
                                                  Qt::MatchExactly).first()->row();
    ui ->userTableWidget ->removeRow(rowNum);
    ui ->messageBrower ->setTextColor(Qt::gray);
    ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
    ui ->messageBrower ->append(tr("%1 于 %2离开!").arg(userName).arg(time));
    ui ->userNumLabel ->setText(tr("在线人数:%1")
                                .arg(ui ->userTableWidget ->rowCount()));
}
 
void Widget::sendMessage(MessageType type, QString serverAddress)
{
    QByteArray data;
    QDataStream out(&data, QIODevice::WriteOnly);
    QString localHostName = QHostInfo::localHostName();
    QString address = getIp();
 
    out << type << getUserName() << localHostName;
 
    switch (type)
    {
        case Message:
            if(ui->messageTextEdit->toPlainText() == "")
            {
                QMessageBox::warning(0, tr("警告"),
                                     tr("发送内容不能为空"), QMessageBox::Ok);
                return;
            }
 
            out << address << getMessage();
            ui -> messageBrower -> verticalScrollBar()
                    ->setValue(ui->messageBrower->verticalScrollBar()->maximum());
 
        break;
 
    case NewParticipant:
        out << address;
        break;
 
    case ParticipantLeft:
        break;
 
    case FileName:
    {
        int row = ui ->userTableWidget ->currentRow();
        QString clientAddress = ui ->userTableWidget ->item(row, 2) ->text();
        out << address << clientAddress << fileName;
        break;
    }
 
    case Refuse:
        out << serverAddress;
        break;
 
    default:
        break;
    }
 
    qDebug("%s:%d, type = %d, userName = %s, localHostName = %s, ipAddress = %s",
           __FUNCTION__,
           __LINE__,
           type,
           getUserName().toStdString().data(),
           localHostName.toStdString().data(),
           address.toStdString().data());
 
    udpSocket->writeDatagram(data, QHostAddress::Broadcast, port);
//    udpSocket->flush();
//    udpSocket ->waitForBytesWritten();
}
 
void Widget::closeEvent(QCloseEvent *event)
{
    sendMessage(ParticipantLeft);
    QWidget::closeEvent(event);
}
 
QString Widget::getIp()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
 
    foreach(QHostAddress address, list)
    {
        //扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
        if(address.protocol() == QAbstractSocket::IPv4Protocol
                && !address.toString().startsWith("169")
                && !address.toString().startsWith("127"))
        {
           return address.toString();
        }
    }
 
    return 0;
}
 
QString Widget::getUserName()
{
    QStringList envVariables;
    envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
                 << "HOSTNAME.*" << "DOMAINNAME.*";
    QStringList environment = QProcess::systemEnvironment();
    foreach (QString string, envVariables)
    {
        int index = environment.indexOf(QRegExp(string));
        if (index != -1)
        {
 
            QStringList stringList = environment.at(index).split('=');
            if (stringList.size() == 2)
            {
                return stringList.at(1);
                break;
            }
        }
    }
    return "unknown";
}
 
QString Widget::getMessage()
{
    QString msg = ui ->messageTextEdit ->toHtml();
    ui ->messageTextEdit ->clear();
    ui ->messageTextEdit ->setFocus();
    return msg;
}
 
bool Widget::saveFile(const QString &fileName)
{
    QFile file(fileName);
    if(!file.open(QFile::WriteOnly | QFile::Text))
    {
        QMessageBox::warning(this, tr("保存文件"),
                             tr("无法保存文件 %1 %2").arg(fileName)
                             .arg(file.errorString()));
        return false;
    }
 
    QTextStream out(&file);
    out << ui ->messageBrower ->toPlainText();
    return true;
}
 
void Widget::hasPendingFile(QString userName, QString serverAddress, QString clientAddress, QString fileName)
{
    QString ipAddress = getIp();
    if(ipAddress == clientAddress)
    {
        int btn = QMessageBox::information(this,tr("接受文件"),
                                           tr("来自%1(%2)的文件:%3,是否接收?")
                                           .arg(userName).arg(serverAddress).arg(fileName),
                                           QMessageBox::Yes,QMessageBox::No);
        if (btn == QMessageBox::Yes) {
            QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);
            if(!name.isEmpty())
            {
                tcpClient *client = new tcpClient(this);
                client->setFileName(name);
                client->setHostAddress(QHostAddress(serverAddress));
                client->show();
            }
        } else {
            sendMessage(Refuse, serverAddress);
        }
    }
}
 
void Widget::processPendingDatagrams()
{
    qDebug("%s:%d", __FUNCTION__, __LINE__);
 
    while(udpSocket ->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket ->pendingDatagramSize());
        udpSocket ->readDatagram(datagram.data(), datagram.size());
        QDataStream in(&datagram, QIODevice::ReadOnly);
 
        int messageType;
        in >> messageType;
        QString userName, localHostName, ipAddress, message;
        QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
 
        qDebug("%s:%d, type = %d", __FUNCTION__, __LINE__, messageType);
 
        switch (messageType) {
        case Message:
            in >> userName >> localHostName >> ipAddress >> message;
            ui ->messageBrower ->setTextColor(Qt::blue);
            ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 12));
            ui ->messageBrower ->append("[" + userName + "]" + time);
            ui ->messageBrower ->append(message);
 
            break;
 
        case NewParticipant:
            in >> userName >> localHostName >> ipAddress;
            newParticipant(userName, localHostName, ipAddress);
 
            break;
 
        case ParticipantLeft:
            in >> userName >> localHostName;
            participantLeft(userName, localHostName, time);
            break;
 
        case FileName:
        {
            in >> userName >> localHostName >> ipAddress;
            QString clientAddress, fileName;
            in >> clientAddress >> fileName;
            hasPendingFile(userName, ipAddress, clientAddress, fileName);
            break;
        }
 
        case Refuse:
        {
            in >> userName >> localHostName;
            QString serverAddress;
            in >> serverAddress;
            QString ipAddress = getIp();
            if(ipAddress == serverAddress)
            {
                server ->refused();
            }
            break;
        }
 
        default:
            break;
 
        }
    }
}
 
 
void Widget::on_sendButton_clicked()
{
    sendMessage(Message);
}
 
void Widget::getFileName(QString name)
{
    fileName = name;
    sendMessage(FileName);
}
 
void Widget::on_sendToolBtn_clicked()
{
    if(ui->userTableWidget ->selectedItems().isEmpty())
    {
        QMessageBox::warning(0, tr("选择用户"),
                             tr("请先从用户列表选择要传送的用户!"), QMessageBox::Ok);
        return;
    }
 
    server ->show();
    server ->initServer();
}
 
void Widget::on_fontComboBox_currentFontChanged(const QFont &f)
{
    ui ->messageTextEdit ->setCurrentFont(f);
    ui ->messageTextEdit ->setFocus();
}
 
void Widget::on_sizeComboBox_currentIndexChanged(const QString &arg1)
{
    ui ->messageTextEdit ->setFontPointSize(arg1.toDouble());
    ui ->messageTextEdit ->setFocus();
}
 
void Widget::on_boldToolBtn_clicked(bool checked)
{
    if(checked)
    {
        ui ->messageTextEdit ->setFontWeight(QFont::Bold);
    }
    else
    {
        ui ->messageTextEdit ->setFontWeight(QFont::Normal);
    }
 
    ui ->messageTextEdit ->setFocus();
}
 
void Widget::on_italicToolBtn_clicked(bool checked)
{
    ui ->messageTextEdit ->setFontItalic(checked);
    ui ->messageTextEdit ->setFocus();
}
 
void Widget::on_underlineToolBtn_clicked(bool checked)
{
    ui ->messageTextEdit ->setFontUnderline(checked);
    ui ->messageTextEdit ->setFocus();
}
 
void Widget::on_colorToolBtn_clicked()
{
    color = QColorDialog::getColor(color, this);
    if(color.isValid())
    {
        ui ->messageTextEdit ->setTextColor(color);
        ui ->messageTextEdit ->setFocus();
    }
}
 
void Widget::currentFormatChanged(const QTextCharFormat &format)
{
    ui ->fontComboBox ->setCurrentFont(format.font());
    //如果字体大小出错(因为我们最小的字体为9),使用12
    if(format.fontPointSize() < 9)
    {
        ui ->sizeComboBox ->setCurrentIndex(3);
    }
    else
    {
        ui ->sizeComboBox ->setCurrentIndex(ui ->sizeComboBox ->findText(QString::number(format.fontPointSize())));
    }
 
    ui ->boldToolBtn ->setChecked(format.font().bold());
    ui ->italicToolBtn ->setChecked(format.font().italic());
    ui ->underlineToolBtn ->setChecked(format.font().underline());
 
    color = format.foreground().color();
}
 
 
void Widget::on_saveToolBtn_clicked()
{
    if(ui ->messageBrower ->document() ->isEmpty())
    {
        QMessageBox::warning(0, tr("警告"),
                             tr("聊天记录为空,无法保存!"), QMessageBox::Ok);
    }
    else
    {
        QString fileName = QFileDialog::getSaveFileName(this,
                                                        tr("保存聊天记录"), tr("聊天记录"), tr("文本(*.txt);;All File(*.*"));
        if(!fileName.isEmpty())
        {
            saveFile(fileName);
        }
    }
}
 
void Widget::on_clearToolBtn_clicked()
{
    ui ->messageBrower ->clear();
}
 
void Widget::on_exitButton_clicked()
{
    close();
}
4.tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
 
#include <QTime>
#include <QDialog>
#include <QFile>
#include <QTcpServer>
#include <QTcpSocket>
 
namespace Ui {
class TcpServer;
}
 
class TcpServer : public QDialog
{
    Q_OBJECT
 
public:
    explicit TcpServer(QWidget *parent = nullptr);
    ~TcpServer();
 
    void initServer();
    void refused();
protected:
    void closeEvent(QCloseEvent *);
 
private slots:
    void on_serverOpenBtn_clicked();
 
    void on_serverSendBtn_clicked();
 
    void on_serverCloseBtn_clicked();
 
    void sendMessage();
 
    void updateClientProgress(qint64 numBytes);
 
signals:
    void sendFileName(QString fileName);
 
private:
    Ui::TcpServer *ui;
    qint16 tcpPort;
    QTcpServer *tcpServer;
    QTcpSocket *clientConnection;
 
    QString fileName;
    QString theFileName;
    QFile *localFile;
 
    qint64 payloadSize;
    qint64 totalBytes;
    qint64 bytesWritten;
    qint64 bytesToWrite;
    QByteArray outBlock;    //缓存一次发送的数据
 
    QTime time; //定时器
};
 
#endif // TCPSERVER_H
5.tcpserver.cpp
#include "tcpserver.h"
#include "ui_tcpserver.h"
 
#include <QFileDialog>
#include <QMessageBox>
 
TcpServer::TcpServer(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::TcpServer)
{
    ui->setupUi(this);
 
    setFixedSize(350, 180);
 
    tcpPort = 6666;
    tcpServer = new QTcpServer(this);
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendMessage()));
 
    initServer();
}
 
TcpServer::~TcpServer()
{
    delete ui;
}
 
void TcpServer::initServer()
{
    payloadSize = 64 * 1024;
    totalBytes = 0;
    bytesWritten = 0;
    bytesToWrite = 0;
 
    ui ->serverStatusLabel ->setText(tr("请选择要传送的文件"));
    ui ->progressBar ->reset();
    ui ->serverOpenBtn ->setEnabled(true);
    ui ->serverSendBtn ->setEnabled(false);
    tcpServer ->close();
}
 
void TcpServer::refused()
{
    tcpServer ->close();
    ui ->serverStatusLabel ->setText(tr("对方拒绝接收!!!"));
}
 
void TcpServer::closeEvent(QCloseEvent *)
{
    on_serverCloseBtn_clicked();
}
 
//打开按钮
void TcpServer::on_serverOpenBtn_clicked()
{
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
    {
        theFileName = fileName.right(fileName.size() - fileName.lastIndexOf("/")-1);
        ui ->serverStatusLabel ->setText(tr("要传送的文件为:%1").arg(theFileName));
        ui ->serverSendBtn ->setEnabled(true);
        ui ->serverOpenBtn ->setEnabled(true);
    }
}
 
//发送按钮
void TcpServer::on_serverSendBtn_clicked()
{
    if(!tcpServer ->listen(QHostAddress::Any, tcpPort))
    {
        qDebug() << tcpServer ->errorString();
        close();
        return;
    }
 
    ui ->serverStatusLabel ->setText(tr("等待对方接收......"));
    emit sendFileName(theFileName);
}
 
void TcpServer::on_serverCloseBtn_clicked()
{
    if(tcpServer ->isListening())
    {
        tcpServer ->close();
        if(localFile ->isOpen())
        {
            localFile ->close();
        }
        clientConnection ->abort();
    }
 
    close();
}
 
void TcpServer::sendMessage()
{
    ui ->serverSendBtn ->setEnabled(false);
    clientConnection = tcpServer ->nextPendingConnection();
    connect(clientConnection, SIGNAL(bytesWritten(qint64)),
            this, SLOT(updateClientProgress(qint64)));
 
    ui ->serverStatusLabel ->setText(tr("开始传送文件 %1!").arg(theFileName));
 
    localFile = new QFile(fileName);
    if(!localFile ->open(QFile::ReadOnly))
    {
        QMessageBox::warning(this, tr("应用程序"), tr("无法读取文件 %1:\n%@").arg(fileName).arg(localFile->errorString()));
        return;
    }
 
    totalBytes = localFile ->size();
    QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
    sendOut.setVersion(QDataStream::Qt_5_9);
    time.start();   //开始计时
    QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf("/") -1);
    sendOut <<qint64(0) << qint64(0) << currentFile;
    totalBytes += outBlock.size();
    sendOut.device() ->seek(0);
    sendOut << totalBytes << qint64(outBlock.size() - sizeof(qint64)*2);
    bytesToWrite = totalBytes - clientConnection ->write(outBlock);
    outBlock.resize(0);
}
 
void TcpServer::updateClientProgress(qint64 numBytes)
{
    bytesWritten += (int)numBytes;
    if(bytesToWrite > 0){
        outBlock = localFile->read(qMin(bytesToWrite,payloadSize));
        bytesToWrite -= (int)clientConnection->write(outBlock);
        outBlock.resize(0);
    }
    else{
        localFile->close();
    }
    ui->progressBar->setMaximum(totalBytes);
    ui->progressBar->setValue(bytesWritten);
 
   float useTime = time.elapsed();
   double speed = bytesWritten / useTime;
   ui->serverStatusLabel->setText(tr("已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
                                  .arg(bytesWritten / (1024*1024))//已发送
                                  .arg(speed*1000/(1024*1024),0,'f',2)//速度
                                  .arg(totalBytes / (1024 * 1024))//总大小
                                  .arg(useTime/1000,0,'f',0)//用时
                                  .arg(totalBytes/speed/1000 - useTime/1000,0,'f',0));//剩余时间
 
   //num.sprintf("%.1f KB/s", (bytesWritten*1000) / (1024.0*time.elapsed()));
    if(bytesWritten == totalBytes)
        ui->serverStatusLabel->setText(tr("传送文件 %1 成功").arg(theFileName));
 
}
 
6.tcpclient.h
 

#ifndef TCPCLIENT_H
#define TCPCLIENT_H
 
#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QTime>
 
namespace Ui {
class tcpClient;
}
 
class tcpClient : public QDialog
{
    Q_OBJECT
 
public:
    explicit tcpClient(QWidget *parent = nullptr);
    ~tcpClient();
    void setHostAddress(QHostAddress address);
    void setFileName(QString fileName);
 
protected:
    void closeEvent(QCloseEvent *);
 
private:
    Ui::tcpClient *ui;
    QTcpSocket *tcpclient;
    quint16 tcpPort;
    quint16 blockSize;
    QHostAddress hostAddress;
 
    qint64 TotalBytes;
    qint64 bytesReceived;
    qint64 bytesToReceive;
    qint64 fileNameSize;
 
    QString fileName;
    QFile *localFile;
    QByteArray inBlock;
 
    QTime time;
 
private slots:
    void on_tcpClientCancelBtn_clicked();
    void on_tcpClientCloseBtn_clicked();
    void newConnect();
    void readMessage();
    void displayError(QAbstractSocket::SocketError socketError);
 
};
 
#endif // TCPCLIENT_H
 7.tcpclient.cpp
 

#include "tcpclient.h"
#include "ui_tcpclient.h"
 
#include <QMessageBox>
 
tcpClient::tcpClient(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::tcpClient)
{
    ui->setupUi(this);
 
    setFixedSize(350, 180);
 
    TotalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
 
    tcpclient = new QTcpSocket(this);
    tcpPort = 6666;
 
    connect(tcpclient, SIGNAL(readyRead()), this, SLOT(readMessage()));
    connect(tcpclient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
 
tcpClient::~tcpClient()
{
    delete ui;
}
 
void tcpClient::setHostAddress(QHostAddress address)
{
    hostAddress = address;
    newConnect();
}
 
void tcpClient::setFileName(QString fileName)
{
    localFile = new QFile(fileName);
}
 
void tcpClient::closeEvent(QCloseEvent *)
{
    on_tcpClientCloseBtn_clicked();
}
 
void tcpClient::newConnect()
{
    blockSize = 0;
    tcpclient ->abort();
    tcpclient ->connectToHost(hostAddress, tcpPort);
    time.start();
}
 
void tcpClient::readMessage()
{
    QDataStream in(tcpclient);
    in.setVersion(QDataStream::Qt_4_7);
 
    float useTime = time.elapsed();
 
    if (bytesReceived <= sizeof(qint64)*2) {
        if ((tcpclient->bytesAvailable()
             >= sizeof(qint64)*2) && (fileNameSize == 0))
        {
            in>>TotalBytes>>fileNameSize;
            bytesReceived += sizeof(qint64)*2;
        }
        if((tcpclient->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
            in>>fileName;
            bytesReceived +=fileNameSize;
 
            if(!localFile->open(QFile::WriteOnly))
            {
                QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.")
                                     .arg(fileName).arg(localFile->errorString()));
                return;
            }
        }
        else
        {
            return;
        }
    }
    if (bytesReceived < TotalBytes) {
        bytesReceived += tcpclient->bytesAvailable();
        inBlock = tcpclient->readAll();
        localFile->write(inBlock);
        inBlock.resize(0);
    }
    ui->progressBar->setMaximum(TotalBytes);
    ui->progressBar->setValue(bytesReceived);
 
    double speed = bytesReceived / useTime;
    ui->tcpClientStatusLabel->setText(tr("已接收 %1MB (%2MB/s) "
                                         "\n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
                                      .arg(bytesReceived / (1024*1024))
                                      .arg(speed*1000/(1024*1024),0,'f',2)
                                      .arg(TotalBytes / (1024 * 1024))
                                      .arg(useTime/1000,0,'f',0)
                                      .arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));
 
    if(bytesReceived == TotalBytes)
    {
        localFile->close();
        tcpclient->close();
        ui->tcpClientStatusLabel->setText(tr("接收文件 %1 完毕")
                                          .arg(fileName));
    }
}
 
void tcpClient::displayError(QAbstractSocket::SocketError socketError)
{
    switch (socketError) {
    case QAbstractSocket::RemoteHostClosedError:
        break;
    default:
        qDebug() << tcpclient ->errorString();
    }
}
 
void tcpClient::on_tcpClientCancelBtn_clicked()
{
    tcpclient ->abort();
    if(localFile ->isOpen())
    {
        localFile ->close();
    }
}
 
void tcpClient::on_tcpClientCloseBtn_clicked()
{
    tcpclient ->abort();
    if(localFile ->isOpen())
    {
        localFile ->close();
    }
    close();
}
 注意事项:
1.确保本地只有一个网卡启用,要不然会获取到很多IP地址;如果电脑连接到路由器的话,你有可能会获取到169开头的IP地址:169.254.xx.xx, 169开头的是私有地址,没法使用,以下是获取本地IP地址的代码

QString Widget::getIp()
{
    QList<QHostAddress> list = QNetworkInterface::allAddresses();
 
    foreach(QHostAddress address, list)
    {
        //扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
        if(address.protocol() == QAbstractSocket::IPv4Protocol
                && !address.toString().startsWith("169")
                && !address.toString().startsWith("127"))
        {
           return address.toString();
        }
    }
 
    return 0;
}
源码下载
https://download.csdn.net/download/guoyunfei123/12261023
————————————————
版权声明:本文为CSDN博主「tiankong19999」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guoyunfei123/article/details/105014590

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_2913.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Ps 2022在M1 mac上导出 PNG 格式发生未知错误如何解决?

Photoshop 2022 for mac 在M1上导出 PNG 时,会提示“发生了未知错误”,即使点击“导出”按钮,导出的图片也是一个空白文件。小编教给大家 Ps 2021在 M1 mac上导出 PNG 格式发生未知错误的解决方法。1.打开 PhotoShop 的首选项 >常规,如下图所示:(也可以通过快捷键 Com…

图数据库入门教程(二)认识tinkerpop与gremlin

上一篇文章我们对图数据库有了一个简单的理解,对于关系的计算优雅而快速,适用与一些关系计算的场景,比如社交网络、金融反欺诈、商机发现、智能推荐等,想了解更多可以看一下阿里云gdb的文档https://help.aliyun.com/document_detail/112465.html。 当前图数据库天下的形式 …

设计模式之(3)——抽象工厂方法模式

定义:抽象工厂模式简单地讲,就是提供一个超级工厂,围绕这个超级工厂创建其他工厂;抽象工厂模式提供一个创建一些列相关或者相互依赖对象的接口;在此之前我们先来讲一下产品等级和产品族的概念;相同的产品等级就是相同的同一类的产品,比如美的冰箱、格力冰箱、海尔冰箱,…

Mysql----事务

《需求》 《操作》 《细节》

分类数据展示功能_缓存优化_分析

分类数据展示功能_缓存优化_分析 对数据进行一个缓存优化,分析发现:分类的数据在每一次页面加载后会重新请求数据库来加载,对数据库的压力比较大,而且这数据不会经常发送变化,可使用redis来缓存这个数据 分类数据展示功能_缓存优化_代码实现public class CategoryServiceI…

日常问题: 上线确认

作为开发,手头没事的时候,担心自己没参与大项目,年终没产出。而真正需求到来的时候,却是狂风暴雨一般,密集且时间紧迫。在紧锣密鼓996之后,终于迎来了上线。 但这一天不太顺利。背景 xxx正式上线。上线前,方案强调要开发把所有配置都给到他,他要确认下。当时觉得有问题…

第一个代码Hello World!

HelloWorld新建一个文件夹,存放代码新建一个Java文件 文件后缀为.java名为Hello.java[注意]要显示系统后缀名编写代码 public class Hello{ public static void main(String[] arge){ System.out.print("Hello,World!"); }} 打开cmd 路径需要是Hello.j…

Linux

1、关机命令命令 说明sync 将数据由内存同步到硬盘中shutdown 关机shutdown -h 10 10分钟后关机shutdown -h now 立马关机shutdown -h 20:25 指定时间关机shutdown -h +10 10分钟后关机shutdown -r now 系统立马重启shutdown -r +10 10分钟后重启reboot 重启,等于shutdown -r …

线性布局LinearLayout

线性布局中的下级视图有两种排列方式当orientation属性为horizontal时,线性布局中的下级视图在水平方向上从左往右排列 当orientation属性为vetical时,线性布局中的下级视图在垂直方向上从上往下排列线性布局的权重 概念:线性布局的权重,用来表示线性布局中各视图所占比例大…

NC50439 tokitsukaze and Soldier

在一个游戏中,tokitsukaze需要在n个士兵中选出一些士兵组成一个团去打副本。 第i个士兵的战力为v[i],团的战力是团内所有士兵的战力之和。 但是这些士兵有特殊的要求:如果选了第i个士兵,这个士兵希望团的人数不超过s[i]。(如果不选第i个士兵,就没有这个限制。) tokitsukaz…

Dos命令

打开cmdwin+r ->cmd 以管理员身份运行win->windows系统->命令提示符->右键->更多->以管理员身份运行 常用的Dos命令 盘符切换 输入D: 切到D盘 查看当前目录下的所有文件 dir 切换目录 cd (change directory) cd msicheng 从Users文件夹进入其子文件夹msiche…

个人网盘搭建——搭建Cloudreve并对接onedrive

前言 搭建这个主要是为了方便自己备份,顺便可以水一下文章(bushi) 其次是自己有好几个微软的全局账号吃灰,还是想稍微利用一下的,如果有人要子号可以来联系哦,好心的我应该会给你的吧 由于个人使用,不会介绍很难的安装方法。下面会介绍宝塔简单快速的安装方法。后续也许…

Spring学习笔记(三)——Spring依赖注入

1.Spring Bean属性注入的几种方式 1.1构造函数注入 使用构造函数实现属性注入大致步骤如下:在 Bean 中添加一个有参构造函数,构造函数内的每一个参数代表一个需要注入的属性; 在 Spring 的 XML 配置文件中,通过 <beans> 及其子元素 <bean> 对 Bean 进行定义; …

动态规划算法(背包问题)

1.应用场景-背包问题 背包问题:有一个背包,容量为4磅 ,现有如下物品1)要求达到的目标为装入的背包的总价值最大,并且重量不超出 2)要求装入的物品不能重复 2.动态规划算法介绍 1)动态规划(Dynamic Programming)算法的核心思想是:将大问题划分为小问题进行解决,从而一步步…

开启apache服务器gzip压缩

开启apache服务器gzip压缩-百度经验 https://jingyan.baidu.com/article/db55b609a7bc234ba20a2f7e.html 从服务端优化来说,通过对服务端做压缩配置可以大大减小文本文件的体积,从而使加载文本的速度成倍的加快。目前比较通用的压缩方法是启用gzip压缩。它会把浏览器请求的页…

Linux修改主机静态IP

通过VIM编辑器打开主机配置文件夹vim /etc/sysconfig/network-scripts/ifcfg-ens33修改IP地址为静态地址BOOTPROTO="static"添加静态IP地址和网关IP 地址 IPADDR=192.168.244.100 网关 GATEWAY=192.168.244.2 域名解析器 DNS1=192.168.244.2网络重启service network …

点击按钮收藏

分析 后台代码RouteServlet类:/*** 添加收藏* @param request* @param response* @throws ServletException* @throws IOException*/public void addFavorite(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {//1、获取线…

前端5JQ

js获取用户输入 JS类属性操作 JS样式操作 事件 JS事件案例 JQuery类库 JQuery基本使用 基本筛选器(了解) 表单筛选器Js获取用户输入 普通数据(输入,选择) ​ 标签对象.value 获取文件数据的时候: 标签对象.value只能获取到文件路径,而标签对象.files结果是一个数组,可以通…

前端Day10

视口(viewport):浏览器显示页面内容的屏幕区域。分为布局视口、视觉视口、理想视口。 布局视口: 视觉视口: 理想视口: meta视口标签: width=device-width:布局视口宽度为当前设备宽度* user-scalable=no:不允许用户缩放 二倍图: 1.物理像素比: ①物理像素:即分辨…

分布式系统的session共享问题

目前大多数大型网站的服务器都采用了分布式服务集群的部署方式。所谓集群,就是让一组计算机服务器协同工作,解决大并发,大数据量瓶颈问题。但是在服务集群中,session共享往往是一个比较头疼的问题。因为session是在服务器端保存的,如果用户跳转到其他服务器的话,session就…