Qt学习笔记-带TCP数据传输的局域网聊天软件
程序运行截图如下:
然后选择一个文件,进行传输。
程序结构如下:
代码如下:
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数据传输的局域网聊天软件相关推荐
- QT学习笔记(TCP 通信)
TCP 通信 TCP 简介 TCP 协议(Transmission Control Protocol)全称是传输控制协议是一种面向连接的.可靠的. 基于字节流的传输层通信协议. TCP 通信必须先建立 ...
- Qt学习笔记-简单的UDP广播包聊天室
运行截图如下: 代码如下: widget.h #ifndef WIDGET_H #define WIDGET_H #include <QWidget> class QUdpSocket; ...
- Qt学习笔记之数据库
一.数据库简介 1.1.数据和数据库(DB) 用计算机进行数据处理,首先就要把信息以数据形式存储到计算机中,故数据是可以被计算机接受和处理的符号.根据所表示的信息特征不同,数据有不同的类别,如数字.文 ...
- QT学习笔记(四):Qt5+MSVC编译 中文字符显示乱码问题解决
QT学习笔记(四):Qt5+MSVC编译 中文字符显示乱码问题解决 问题: 1.解决方法一: 2.解决方法二: 3.解决方法三: 4.解决方法四: 结果显示: Qt5+MSVC编译 中文字符显示乱码. ...
- QT学习笔记(三):Qt软件打包发布(QT5.8 _msvc2013_64+Win10_64)
QT学习笔记(三):Qt软件打包发布(QT5.8 _msvc2013_64+Win10_64) 1.编译方式介绍: 2.动态编译方式打包发布QT程序: 方法一:手动复制 方法二:使用工具 问题& ...
- QT学习笔记(摘抄)
QT学习笔记-1.QT主要的对象 说来惭愧学习c++很长时间了一直没有使用c++开发过软件界面 所以现在想认认真真的学习一个c++图形界面框架库 本来想学习Xwidget但是这个资料不大好找 有啥问题 ...
- 【QT学习笔记】基于QT的天气预报
[QT学习笔记]基于QT的天气预报 前言 那就开始吧! 先看一下效果 颜面最重要,画个UI 构造实现 怎么开始? 开始解析数据 关于城市切换 ok 最后源码献上 感谢 前言 学习qt已经有一段时间了, ...
- Qt学习笔记,Qt国际化
Qt学习笔记,Qt国际化 Qt国际化步骤: 第一步:设置.pro文件,加入TRANSLATIONS为国际化做准备 TRANSLATIONS = language/language_en.ts\ ...
- Qt学习笔记,Qt程序架构设计要旨
Qt学习笔记,Qt程序架构设计要旨 时间过得很快,转眼学习Qt已经有一个多月了,对Qt的学习也在不断的深入中.自己手下的code也很多了,不过不得不说,还有很多的部分没有接触过,比如网络编程,2D,3 ...
最新文章
- 数据院跨学科交叉人才培养走出国门——中德交换生项目首位社科学子赴德国哥廷根大学交流学习
- 云计算的优势有这6点
- list-style样式不显示问题
- 关于工程技术中PE、ME、TE、IE、EE的解说
- OpenStack入门科普,看这一篇就够啦!
- unity底层运行机制_Unity跨平台的机制原理
- 【恋上数据结构】基数排序、桶排序、休眠排序
- 棋盘上的麦粒c语言,棋盘上的麦粒
- 矢量图片转换 emf to eps
- js alert追加html,利用JQ来美化Js的alert弹出框
- linux解压win10iso,ISO文件的解压和WINISO問題
- 19841227同生缘
- selectpicker的使用方法
- 广告片制作技巧分享。
- 水仙花案例与嵌套循环案例
- Python实现多图合并成长图脚本
- 文档格式转换工具对比
- 软件测试之linux——自动化
- 没有图片显示默认图片
- [P2698][USACO12MAR]花盆Flowerpot