程序运行截图如下:

然后选择一个文件,进行传输。

程序结构如下:

代码如下:

tcpreceiver.h

#ifndef TCPRECEIVER_H
#define TCPRECEIVER_H#include <QWidget>
#include <QAbstractSocket>
#include <QTcpServer>
class QTcpSocket;
class QFile;namespace Ui {
class TcpReceiver;
}class TcpReceiver : public QWidget
{Q_OBJECTpublic:explicit TcpReceiver(const int port,QWidget *parent = 0);~TcpReceiver();public slots:void start();void acceptConnection();void updateServerProgress();void displayError(QAbstractSocket::SocketError socketError);void startBtnClicked();private:Ui::TcpReceiver *ui;QTcpServer m_tcpServer;QTcpSocket *m_tcpServerConnection;qint64 m_totalBytes;qint64 m_bytesReceived;qint64 m_fileNameSize;QString m_fileName;QFile *m_localFile;QByteArray m_inBlock;int m_port;
};#endif // TCPRECEIVER_H

tcpsender.h

#ifndef TCPSENDER_H
#define TCPSENDER_H#include <QWidget>
#include <QAbstractSocket>
class QTcpSocket;
class QFile;namespace Ui {
class TcpSender;
}class TcpSender : public QWidget
{Q_OBJECTpublic:explicit TcpSender(const QString ip,const QString port,QWidget *parent = 0);~TcpSender();public slots:void openFile();void send();void startTransfer();void updateClientProgress(qint64);void displayError(QAbstractSocket::SocketError);void openBtnClicked();void sendBtnClicked();private:Ui::TcpSender *ui;QTcpSocket *m_tcpClient;QFile *m_localFile;qint64 m_totalBytes;qint64 m_bytesWritten;qint64 m_bytesToWrite;qint64 m_payloadSize;QString m_fileName;QByteArray m_outBlock;
};#endif // TCPSENDER_H

widget.h

#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>class QUdpSocket;
class TcpSender;
class TcpReceiver;namespace Ui {
class Widget;
}class Widget : public QWidget
{Q_OBJECTpublic:explicit Widget(QWidget *parent = 0);~Widget();public slots:void dataReceived();void btnClicked();void widgetEnable(QString data);void setPortBtnClickd();void peerLineEditChange(QString data);void sendFileBtnClicked();private:Ui::Widget *ui;QUdpSocket *m_udpSocket;TcpSender *m_tcpSender;TcpReceiver *m_tcpReceiver;QString m_peerIp;
};#endif // WIDGET_H

main.cpp

#include "widget.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

tcpreceiver.cpp

#include "tcpreceiver.h"
#include "ui_tcpreceiver.h"#include <QtNetwork>
#include <QDebug>TcpReceiver::TcpReceiver(const int port, QWidget *parent) :QWidget(parent),ui(new Ui::TcpReceiver)
{ui->setupUi(this);m_port=port;connect(&m_tcpServer,SIGNAL(newConnection()),this,SLOT(acceptConnection()));connect(ui->startButton,SIGNAL(clicked(bool)),this,SLOT(startBtnClicked()));
}void TcpReceiver::start(){if(!m_tcpServer.listen(QHostAddress::LocalHost,m_port)){qDebug()<<m_tcpServer.errorString();close();return;}ui->startButton->setEnabled(false);m_totalBytes=0;m_bytesReceived=0;m_fileNameSize=0;ui->serverStatusLabel->setText("监听");ui->serverProgressBar->reset();
}void TcpReceiver::acceptConnection(){m_tcpServerConnection=m_tcpServer.nextPendingConnection();connect(m_tcpServerConnection,SIGNAL(readyRead()),this,SLOT(updateServerProgress()));connect(m_tcpServerConnection,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));ui->serverStatusLabel->setText("接受连接");//关闭服务器不再监听,直接进入数据收发m_tcpServer.close();
}void TcpReceiver::updateServerProgress(){QDataStream in(m_tcpServerConnection);in.setVersion(QDataStream::Qt_5_7);// 如果接收到的数据小于16个字节,保存到来的文件头结构if (m_bytesReceived<=sizeof(qint64)*2){if((m_tcpServerConnection->bytesAvailable()>=sizeof(qint64)*2)&&(m_fileNameSize==0)){// 接收数据总大小信息和文件名大小信息in>>m_totalBytes>>m_fileNameSize;m_bytesReceived +=sizeof(qint64)*2;}if((m_tcpServerConnection->bytesAvailable()>=m_fileNameSize)&&(m_fileNameSize!=0)){// 接收文件名,并建立文件in>>m_fileName;ui->serverStatusLabel->setText(tr("接收文件 %1 …").arg(m_fileName));m_bytesReceived+=m_fileNameSize;m_localFile = new QFile(m_fileName);if (!m_localFile->open(QFile::WriteOnly)){qDebug() << "server: open file error!";return;}}else{return;}}// 如果接收的数据小于总数据,那么写入文件if(m_bytesReceived<m_totalBytes) {m_bytesReceived+=m_tcpServerConnection->bytesAvailable();m_inBlock = m_tcpServerConnection->readAll();m_localFile->write(m_inBlock);m_inBlock.resize(0);}ui->serverProgressBar->setMaximum(m_totalBytes);ui->serverProgressBar->setValue(m_bytesReceived);// 接收数据完成时if (m_bytesReceived==m_totalBytes){m_tcpServerConnection->close();m_localFile->close();ui->startButton->setEnabled(true);ui->serverStatusLabel->setText(tr("接收文件 %1 成功!").arg(m_fileName));}
}void TcpReceiver::displayError(QAbstractSocket::SocketError socketError){Q_UNUSED(socketError)qDebug()<<m_tcpServerConnection->errorString();m_tcpServerConnection->close();ui->serverProgressBar->reset();ui->serverStatusLabel->setText("服务端就绪");ui->startButton->setEnabled(true);
}void TcpReceiver::startBtnClicked(){start();
}TcpReceiver::~TcpReceiver()
{delete ui;
}

tcpsender.cpp

#include "tcpsender.h"
#include "ui_tcpsender.h"#include <QtNetwork>
#include <QFileDialog>TcpSender::TcpSender(const QString ip, const QString port, QWidget *parent) :QWidget(parent),ui(new Ui::TcpSender)
{ui->setupUi(this);ui->hostLineEdit->setText(ip);ui->portLineEdit->setText(port);ui->hostLineEdit->setEnabled(false);ui->portLineEdit->setEnabled(false);m_payloadSize=64*1024;m_totalBytes=0;m_bytesWritten=0;m_bytesToWrite=0;m_tcpClient=new QTcpSocket(this);connect(m_tcpClient,SIGNAL(connected()),this,SLOT(startTransfer()));connect(m_tcpClient,SIGNAL(bytesWritten(qint64)),this,SLOT(updateClientProgress(qint64)));connect(m_tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));connect(ui->sendButton,SIGNAL(clicked(bool)),this,SLOT(sendBtnClicked()));connect(ui->openButton,SIGNAL(clicked(bool)),this,SLOT(openBtnClicked()));
}void TcpSender::openFile(){m_fileName=QFileDialog::getOpenFileName(this);if(!m_fileName.isEmpty()){ui->sendButton->setEnabled(true);ui->clientStatusLabel->setText(QString("打开文件 %1 成功!").arg(m_fileName));}
}void TcpSender::send(){ui->sendButton->setEnabled(false);m_bytesWritten=0;ui->clientStatusLabel->setText("连接中...");m_tcpClient->connectToHost(ui->hostLineEdit->text(),ui->portLineEdit->text().toInt());
}void TcpSender::startTransfer(){m_localFile=new QFile(m_fileName);if(!m_localFile->open(QFile::ReadOnly)){qDebug()<<"client:open file error!";return;}m_totalBytes=m_localFile->size();QDataStream sendOut(&m_outBlock,QIODevice::WriteOnly);sendOut.setVersion(QDataStream::Qt_5_7);QString currentFileName=m_fileName.right(m_fileName.size()-m_fileName.lastIndexOf('/')-1);//文件总大小、文件名大小、文件名sendOut<<qint64(0)<<qint64(0)<<currentFileName;m_totalBytes+=m_outBlock.size();sendOut.device()->seek(0);sendOut<<m_totalBytes<<qint64(m_outBlock.size()-sizeof(qint64)*2);m_bytesToWrite=m_totalBytes-m_tcpClient->write(m_outBlock);ui->clientStatusLabel->setText("已连接");m_outBlock.resize(0);
}void TcpSender::updateClientProgress(qint64 numBytes){m_bytesWritten+=(int)numBytes;if(m_bytesToWrite>0){m_outBlock=m_localFile->read(qMin(m_bytesToWrite,m_payloadSize));m_bytesToWrite-=(int)m_tcpClient->write(m_outBlock);m_outBlock.resize(0);}else{m_localFile->close();}ui->clientProgressBar->setMaximum(m_totalBytes);ui->clientProgressBar->setValue(m_bytesWritten);if(m_bytesWritten==m_totalBytes){ui->clientStatusLabel->setText(QString("传送文件 %1 成功").arg(m_fileName));m_localFile->close();m_tcpClient->close();}
}void TcpSender::displayError(QAbstractSocket::SocketError){qDebug()<<m_tcpClient->errorString();m_tcpClient->close();ui->clientProgressBar->reset();ui->clientStatusLabel->setText("客户端就绪");ui->sendButton->setEnabled(true);
}void TcpSender::openBtnClicked(){ui->clientProgressBar->reset();ui->clientStatusLabel->setText("状态:等待打开文件!");openFile();
}void TcpSender::sendBtnClicked(){send();
}TcpSender::~TcpSender()
{delete ui;
}

widget.cpp

#include "widget.h"
#include "ui_widget.h"#include <QMessageBox>
#include <QHostAddress>
#include <QUdpSocket>
#include "tcpsender.h"
#include "tcpreceiver.h"Widget::Widget(QWidget *parent) :QWidget(parent),ui(new Ui::Widget)
{ui->setupUi(this);ui->inputLineEdit->setEnabled(false);ui->sendPushButton->setEnabled(false);ui->peerLineEdit->setEnabled(false);ui->userLineEdit->setEnabled(false);ui->sendFilePushButton->setEnabled(false);connect(ui->userLineEdit,SIGNAL(textChanged(QString)),this,SLOT(widgetEnable(QString)));connect(ui->setPortPushButton,SIGNAL(clicked(bool)),this,SLOT(setPortBtnClickd()));connect(ui->peerLineEdit,SIGNAL(textEdited(QString)),this,SLOT(peerLineEditChange(QString)));connect(ui->sendFilePushButton,SIGNAL(clicked(bool)),this,SLOT(sendFileBtnClicked()));
}Widget::~Widget()
{delete ui;
}void Widget::dataReceived(){while(m_udpSocket->hasPendingDatagrams()){QByteArray datagram;QHostAddress peerIp;datagram.resize(m_udpSocket->pendingDatagramSize());m_udpSocket->readDatagram(datagram.data(),datagram.size(),&peerIp);ui->listWidget->insertItem(0,QString::fromLocal8Bit(datagram.data()));m_peerIp=peerIp.toIPv4Address();QString temp=QString::fromLocal8Bit(datagram.data()).right(4);qDebug()<<"temp:"<<temp;if(temp=="发送文件"){m_tcpReceiver=new TcpReceiver(ui->portLineEdit->text().toInt());m_tcpReceiver->show();}}
}void Widget::btnClicked()
{QString msg=ui->userLineEdit->text()+QString::fromLocal8Bit(" > ")+ui->inputLineEdit->text();QByteArray datagram=msg.toLocal8Bit();qDebug()<<"msg:"<<msg<<"msg.size"<<msg.size();m_udpSocket->writeDatagram(datagram,datagram.size(),QHostAddress::Broadcast,ui->peerLineEdit->text().toInt());ui->listWidget->insertItem(0,"我 > "+ui->inputLineEdit->text());
}void Widget::widgetEnable(QString data)
{if(!data.isEmpty()){ui->inputLineEdit->setEnabled(true);ui->sendPushButton->setEnabled(true);ui->sendFilePushButton->setEnabled(true);}
}void Widget::setPortBtnClickd()
{m_udpSocket=new QUdpSocket(this);connect(m_udpSocket,SIGNAL(readyRead()),this,SLOT(dataReceived()));if(!m_udpSocket->bind(ui->portLineEdit->text().toInt(),QUdpSocket::ShareAddress|QUdpSocket::ReuseAddressHint)){QMessageBox::information(this,"错误","端口绑定失败");return;}connect(ui->sendPushButton,SIGNAL(clicked(bool)),this,SLOT(btnClicked()));ui->peerLineEdit->setEnabled(true);
}void Widget::peerLineEditChange(QString data)
{if(!data.isEmpty()){ui->userLineEdit->setEnabled(true);}
}void Widget::sendFileBtnClicked()
{QString msg=ui->userLineEdit->text()+QString::fromLocal8Bit(" > ")+"发送文件";QByteArray datagram=msg.toLocal8Bit();qDebug()<<"msg:"<<msg<<"msg.size"<<msg.size();m_udpSocket->writeDatagram(datagram,datagram.size(),QHostAddress::Broadcast,ui->peerLineEdit->text().toInt());ui->listWidget->insertItem(0,"我 > 发送文件");m_tcpSender=new TcpSender("127.0.0.1",ui->peerLineEdit->text());   //使用本地回环,暂时写死m_tcpSender->show();
}

Qt学习笔记-带TCP数据传输的局域网聊天软件相关推荐

  1. QT学习笔记(TCP 通信)

    TCP 通信 TCP 简介 TCP 协议(Transmission Control Protocol)全称是传输控制协议是一种面向连接的.可靠的. 基于字节流的传输层通信协议. TCP 通信必须先建立 ...

  2. Qt学习笔记-简单的UDP广播包聊天室

    运行截图如下: 代码如下: widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> class QUdpSocket; ...

  3. Qt学习笔记之数据库

    一.数据库简介 1.1.数据和数据库(DB) 用计算机进行数据处理,首先就要把信息以数据形式存储到计算机中,故数据是可以被计算机接受和处理的符号.根据所表示的信息特征不同,数据有不同的类别,如数字.文 ...

  4. QT学习笔记(四):Qt5+MSVC编译 中文字符显示乱码问题解决

    QT学习笔记(四):Qt5+MSVC编译 中文字符显示乱码问题解决 问题: 1.解决方法一: 2.解决方法二: 3.解决方法三: 4.解决方法四: 结果显示: Qt5+MSVC编译 中文字符显示乱码. ...

  5. QT学习笔记(三):Qt软件打包发布(QT5.8 _msvc2013_64+Win10_64)

    QT学习笔记(三):Qt软件打包发布(QT5.8 _msvc2013_64+Win10_64) 1.编译方式介绍: 2.动态编译方式打包发布QT程序: 方法一:手动复制 方法二:使用工具 问题& ...

  6. QT学习笔记(摘抄)

    QT学习笔记-1.QT主要的对象 说来惭愧学习c++很长时间了一直没有使用c++开发过软件界面 所以现在想认认真真的学习一个c++图形界面框架库 本来想学习Xwidget但是这个资料不大好找 有啥问题 ...

  7. 【QT学习笔记】基于QT的天气预报

    [QT学习笔记]基于QT的天气预报 前言 那就开始吧! 先看一下效果 颜面最重要,画个UI 构造实现 怎么开始? 开始解析数据 关于城市切换 ok 最后源码献上 感谢 前言 学习qt已经有一段时间了, ...

  8. Qt学习笔记,Qt国际化

    Qt学习笔记,Qt国际化 Qt国际化步骤: 第一步:设置.pro文件,加入TRANSLATIONS为国际化做准备 TRANSLATIONS = language/language_en.ts\     ...

  9. Qt学习笔记,Qt程序架构设计要旨

    Qt学习笔记,Qt程序架构设计要旨 时间过得很快,转眼学习Qt已经有一个多月了,对Qt的学习也在不断的深入中.自己手下的code也很多了,不过不得不说,还有很多的部分没有接触过,比如网络编程,2D,3 ...

最新文章

  1. 数据院跨学科交叉人才培养走出国门——中德交换生项目首位社科学子赴德国哥廷根大学交流学习
  2. 云计算的优势有这6点
  3. list-style样式不显示问题
  4. 关于工程技术中PE、ME、TE、IE、EE的解说
  5. OpenStack入门科普,看这一篇就够啦!
  6. unity底层运行机制_Unity跨平台的机制原理
  7. 【恋上数据结构】基数排序、桶排序、休眠排序
  8. 棋盘上的麦粒c语言,棋盘上的麦粒
  9. 矢量图片转换 emf to eps
  10. js alert追加html,利用JQ来美化Js的alert弹出框
  11. linux解压win10iso,ISO文件的解压和WINISO問題
  12. 19841227同生缘
  13. selectpicker的使用方法
  14. 广告片制作技巧分享。
  15. 水仙花案例与嵌套循环案例
  16. Python实现多图合并成长图脚本
  17. 文档格式转换工具对比
  18. 软件测试之linux——自动化
  19. 没有图片显示默认图片
  20. [P2698][USACO12MAR]花盆Flowerpot

热门文章

  1. 如何在数字化转型战略中真正获得价值?浅谈数字化转型的四个层级
  2. 前面是个主席台的飞鸽传书
  3. Windows Vista SP1 Test Drive发布,在浏览器中即可体验
  4. 2020 年 7 个软件开发趋势
  5. vue实战案例:用学过的知识做一个小demo
  6. 薪酬最高十职位:工程师最吃香
  7. 计算机应用基础综合测试题一,计算机应用基础综合测试题.doc
  8. 这可能是现实版程序员!
  9. 解读文献里的那些图——流式细胞术
  10. FCPX插件:Color Titles动画彩色文本标题