
服务端
serverwidget.h
#ifndef SERVERWIDGET_H#define SERVERWIDGET_H#include <QWidget>#include <QTcpServer> // 监听套接字#include <QTcpSocket> // 通信套接字#include <QFile>#include <QTimer>namespace Ui {class ServerWidget;}class ServerWidget : public QWidget{ Q_OBJECTpublic: explicit ServerWidget(QWidget *parent = 0); ~ServerWidget(); // 发送文件数据的函数 void sendData();private slots: void on_buttonSeleFile_clicked(); void on_buttonSendFile_clicked();private: Ui::ServerWidget *ui; QTcpServer *tcpServer; // 监听套接字 QTcpSocket *tcpSocket; // 通信套接字 QFile file; // 文件对象 QString fileName; // 文件名字 qint64 fileSize; // 文件大小 qint64 sendSize; // 已发送文件大小 // 定时器 QTimer timer;};#endif // SERVERWIDGET_H
serverwidget.cpp
#include "serverwidget.h"#include "ui_serverwidget.h"#include <QFileDialog>#include <QDebug>#include <QFileInfo>ServerWidget::ServerWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ServerWidget){ ui->setupUi(this); this->setWindowTitle("服务器端口为9999"); // 未连接时,两个按钮都不能点击 ui->buttonSeleFile->setEnabled(false); ui->buttonSendFile->setEnabled(false); // 监听套接字 tcpServer = new QTcpServer(this); // 监听ip和端口 tcpServer->listen(QHostAddress::Any, 9999); // 如果客户端成功和服务器连接 // tcpServer会自动触发newConnection() connect(tcpServer, &QTcpServer::newConnection, [=](){ // 取出建立好连接的套接字 tcpSocket = tcpServer->nextPendingConnection(); // 获取对方的ip和端口 QString ip = tcpSocket->peerAddress().toString(); qint16 port = tcpSocket->peerPort(); // 组包 QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port); ui->textEdit->setText(str); // 显示到编辑区 qDebug() << str; // 成功连接后,才能选择文件 ui->buttonSeleFile->setEnabled(true); connect(tcpSocket, &QTcpSocket::readyRead, [=](){ // 获取客户端的信息 QByteArray buf = tcpSocket->readAll(); if(QString(buf) == "file done") { // 文件接收完毕 ui->textEdit->append("客户端文件接收完毕"); // file.close(); // 断开客户端端口 tcpSocket->disconnectFromHost(); tcpSocket->close(); } }); }); // 定时器 connect(&timer, &QTimer::timeout, [=](){ // 关闭定时器 timer.stop(); // 发送文件 sendData(); });}ServerWidget::~ServerWidget(){ delete ui;}// 选择文件按钮void ServerWidget::on_buttonSeleFile_clicked(){ // 文件路径 QString filePath = QFileDialog::getOpenFileName(this, "open", "../"); // 如果选择文件路径有效 if(filePath.isEmpty() == false) { // 先清空前面的内容 fileName.clear(); fileSize = 0; // 获取文件信息 QFileInfo info(filePath); fileName = info.fileName(); fileSize = info.size(); sendSize = 0; // 初始化发送文件的大小 // 只读方式打开, 指定文件的名字 file.setFileName(filePath); // 打开文件 bool isOk = file.open(QIODevice::ReadOnly); if(isOk == false) { qDebug() << "只读方式打开文件失败 85"; } // 提示打开文件的路径 ui->textEdit->append(filePath); ui->buttonSeleFile->setEnabled(false); ui->buttonSendFile->setEnabled(true); }else { qDebug() << "选择文件路径出错 95"; }}// 发送文件按钮void ServerWidget::on_buttonSendFile_clicked(){ ui->buttonSendFile->setEnabled(false); // 先发送文件头信息 文件名##文件大小 QString head = QString("%1##%2").arg(fileName).arg(fileSize); // 发送头部信息 qint64 len = tcpSocket->write(head.toUtf8()); if(len > 0) // 头部信息发送成功 { // 发送正在文件信息 // 防止TCP黏包问题,需要通过定时器延时 timer.start(200); qDebug() << "头部信息发送成功"; }else { qDebug() << "头部信息发送失败 114"; file.close(); ui->buttonSeleFile->setEnabled(true); ui->buttonSendFile->setEnabled(false); }}// 发送数据方法void ServerWidget::sendData(){ ui->textEdit->append("正在发送文件......"); qint64 len = 0; do{ // 每次发送数据的大小 char buf[4*1024] = {0}; len = 0; // 往文件中读数据 len = file.read(buf, sizeof(buf)); // 发送数据, 读多少发多少 len = tcpSocket->write(buf, len); // 发送的数据累加 sendSize += len; qDebug() << "sendSize=" << sendSize << " fileSize=" << fileSize; }while(len > 0); // 是否发送文件完毕 if(sendSize == fileSize) { ui->textEdit->append("文件发送完毕"); file.close(); // 把客户端关了 // tcpSocket->disconnectFromHost(); // tcpSocket->close(); }}
客户端
clientwidget.h
#ifndef CLIENTWIDGET_H#define CLIENTWIDGET_H#include <QWidget>#include <QTcpSocket>#include <QFile>namespace Ui {class ClientWidget;}class ClientWidget : public QWidget{ Q_OBJECTpublic: explicit ClientWidget(QWidget *parent = 0); ~ClientWidget();private slots: void on_buttonConnect_clicked();private: Ui::ClientWidget *ui; QTcpSocket *tcpSocket; QFile file; // 文件对象 QString fileName; // 文件名字 qint64 fileSize; // 文件大小 qint64 recvSize; // 已接收文件大小 bool isStart;};#endif // CLIENTWIDGET_H
clientwidget.cpp
#include "clientwidget.h"#include "ui_clientwidget.h"#include <QDebug>#include <QMessageBox>#include <QHostAddress>ClientWidget::ClientWidget(QWidget *parent) : QWidget(parent), ui(new Ui::ClientWidget){ ui->setupUi(this); // 设置进度条当前值为0 ui->progressBar->setValue(0); this->setWindowTitle("客户端"); // tcpSocket = new QTcpSocket(this); // 与服务器建立连接 connect(tcpSocket, &QTcpSocket::connected, [=](){ // 提示连接成功 ui->textEdit->clear(); ui->textEdit->append("和服务器连接成功,等待服务器传送文件……"); }); isStart = true; connect(tcpSocket, &QTcpSocket::readyRead, [=](){ // 取出接收的内容 QByteArray buf = tcpSocket->readAll(); if(isStart == true) {// 接收头 isStart = false; // 解析头部信息 QString buf = "hello##1024" // 初始化 // 将字节数组buf转为string并拆包 fileName = QString(buf).section("##", 0, 0); fileSize = QString(buf).section("##", 1, 1).toInt(); recvSize = 0; // 打开文件 file.setFileName(fileName); // 只写方式方式,打开文件 bool isOk = file.open(QIODevice::WriteOnly); qDebug() << "isOk" << isOk; if(isOk == false) { qDebug() << "WriteOnly error 35"; tcpSocket->disconnectFromHost(); //断开连接 tcpSocket->close(); //关闭套接字 return; // 如果打开文件失败,中断函数 } // 弹出对话框, 显示接收文件的信息 QString str = QString("接收的文件:[%1: %2kb]").arg(fileName).arg(fileSize/1024); ui->textEdit->append(str); ui->textEdit->append("正在接收文件……"); // 设置进度条 ui->progressBar->setMinimum(0); // 最小值 ui->progressBar->setMaximum(fileSize/1024); ui->progressBar->setValue(0); // 当前值 }else {// 文件信息 qint64 len = file.write(buf); if(len > 0) { recvSize += len; //累计接收大小 qDebug() << len; } // 更新进度条 ui->progressBar->setValue(recvSize/1024); qDebug() << "1111"; // recvSize += len; if(recvSize == fileSize) // 文件接收完毕 { // 先给服务器发送(接收文件完成的信息) tcpSocket->write("file done"); file.close(); // 关闭文件 ui->textEdit->append("文件接收完成"); tcpSocket->disconnectFromHost(); tcpSocket->close(); } } });}ClientWidget::~ClientWidget(){ delete ui;}void ClientWidget::on_buttonConnect_clicked(){ // 获取服务器的ip和端口 QString ip = ui->lineEditIP->text(); quint16 port = ui->lineEditPort->text().toInt(); // 连接服务器 tcpSocket->connectToHost(QHostAddress(ip), port); isStart = true; //设置进度条 ui->progressBar->setValue(0);}
