程序运行截图如下:
然后选择一个文件,进行传输。
程序结构如下:
代码如下:
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_OBJECT public: 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_OBJECT public: 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_OBJECT public: 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(); }