服务器端:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QDialog>
#include <QAbstractSocket>
#include <QTcpServer>
class QTcpSocket;
class QFile;
class MainWindow : public QDialog
{
Q_OBJECT
public:
MainWindow(QDialog *parent = nullptr);
~MainWindow();
private slots:
void start();
void acceptConnection();
void updateServerProgress();
void displayError(QAbstractSocket::SocketError socker_error);
private:
QTcpServer tcp_server_;
QTcpSocket *tcp_server_connection_;
qint64 total_bytes_; //存放总大小信息
qint64 bytes_received_; //已收到数据的大小
qint64 file_name_size_; //文件名的大小信息
QString file_name_;//存放文件名
QFile *local_file_;//本地文件
QByteArray in_block_;//数据缓冲区
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QtNetwork>
MainWindow::MainWindow(QDialog *parent)
: QDialog(parent)
{
//一旦有客户端连接到服务器,则发射newConnection信号
connect(&tcp_server_, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
start();
}
MainWindow::~MainWindow()
{
}
void MainWindow::start()
{
if(!tcp_server_.listen(QHostAddress::LocalHost, 6666)){
qDebug() << tcp_server_.errorString();
close();
return;
}
total_bytes_ = 0;
bytes_received_ = 0;
file_name_size_ = 0;
}
void MainWindow::acceptConnection()
{
tcp_server_connection_ = tcp_server_.nextPendingConnection();
connect(tcp_server_connection_, SIGNAL(readyRead()), this, SLOT(updateServerProgress()));
connect(tcp_server_connection_, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
qDebug() << QString::fromLocal8Bit("接受连接");
//关闭服务器,不在进行监听
tcp_server_.close();
}
void MainWindow::updateServerProgress()
{
QDataStream in(tcp_server_connection_);
in.setVersion(QDataStream::Qt_5_6);
//如果接收到的数据小于16个字节,保存到来的头文件结构
if(bytes_received_ <= sizeof(qint64)*2){
if((tcp_server_connection_->bytesAvailable() >= sizeof(qint64)*2) && (file_name_size_ == 0)){
//接收数据总大小信息和文件名大小信息
in >> total_bytes_ >> file_name_size_;
bytes_received_ += sizeof(qint64)*2;
}
if((tcp_server_connection_->bytesAvailable() >= file_name_size_) && (file_name_size_ != 0)){
//接收文件名,并建立文件
in >> file_name_;
qDebug() << QString::fromLocal8Bit("接收文件");
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");//当前系统时间
bytes_received_ += file_name_size_;
local_file_ = new QFile(file_name_);
if(!local_file_->open(QFile::WriteOnly)){
qDebug() << "server: open file error!";
return;
}
}else{
return;
}
}
//如果接收数据小于总数据,那么写入文件
if(bytes_received_ < total_bytes_){
bytes_received_ += tcp_server_connection_->bytesAvailable();
in_block_ = tcp_server_connection_->readAll();
local_file_->write(in_block_);
in_block_.resize(0);
}
//进度
qDebug() << 100*bytes_received_/total_bytes_;
//接受数据完成时
if(bytes_received_ == total_bytes_){
tcp_server_connection_->close();
local_file_->close();
qDebug() << QString::fromLocal8Bit("接受文件成功");
qDebug() << QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");//当前系统时间
}
}
void MainWindow::displayError(QAbstractSocket::SocketError socker_error)
{
qDebug() << tcp_server_connection_->errorString();
tcp_server_connection_->close();
}
客户端:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QAbstractSocket>
class QTcpSocket;
class QFile;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void openFile();
void send();
void startTransfer();
void updateClientProgress(qint64 num_bytes);
void displayError(QAbstractSocket::SocketError);
private:
QTcpSocket *tcp_client_;
QFile *local_file_; //要发送的文件
qint64 total_bytes_; //发送数据的总大小
qint64 bytes_written_; //已经发送数据大小
qint64 bytes_to_write_; //剩余数据大小
qint64 payload_size_; //每次发送数据的大小
QString file_name_; //保存文件路径
QByteArray out_block_; //数据缓冲区,即存放每次要发送的数据块
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include <QtNetwork>
#include <QFileDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
payload_size_ = 64*1024;//64k
total_bytes_ = 0;
bytes_written_ = 0;
bytes_to_write_ = 0;
tcp_client_ = new QTcpSocket(this);
//连接服务器成功时,会发出connected
connect(tcp_client_, SIGNAL(connected()), this, SLOT(startTransfer()));
//当有数据被写入,发出bytesWritten信号,参数为发出数据的大小
connect(tcp_client_, SIGNAL(bytesWritten(qint64)), this, SLOT(updateClientProgress(qint64)));
connect(tcp_client_, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
openFile();
send();
}
MainWindow::~MainWindow()
{
}
void MainWindow::openFile()
{
file_name_ = QFileDialog::getOpenFileName(this);
if(!file_name_.isEmpty()){
qDebug() << QString::fromLocal8Bit("打开文件成功");
}
}
void MainWindow::send()
{
//初始化已发送字节为0
bytes_written_ = 0;
qDebug() << QString::fromLocal8Bit("连接中...");
//连接服务器
tcp_client_->connectToHost(QHostAddress::LocalHost, 6666);
}
void MainWindow::startTransfer()
{
local_file_ = new QFile(file_name_);
if(!local_file_->open(QFile::ReadOnly)){
qDebug() << "client: open file error!";
return;
}
//获取文件大小
total_bytes_ = local_file_->size();
QDataStream send_out(&out_block_, QIODevice::WriteOnly);
send_out.setVersion(QDataStream::Qt_5_6);
QString current_file_name = file_name_.right(file_name_.size() - file_name_.lastIndexOf('/') - 1);
//保留总大小信息空间、文件名大小信息空间,然后输入文件名
send_out << qint64(0) << qint64(0) << current_file_name;
//这里的总大小是总大小信息、文件名大小信息、文件名和实际文件大小的总和
total_bytes_ += out_block_.size();
send_out.device()->seek(0);
//用实际的大小信息代替两个qint64(0)空间
send_out << total_bytes_ << qint64((out_block_.size() - sizeof(qint64)*2));
//发送完文件头结构后剩余数据的大小
bytes_to_write_ = total_bytes_ - tcp_client_->write(out_block_);
out_block_.resize(0);
}
//发送实际的文件
void MainWindow::updateClientProgress(qint64 num_bytes)
{
//已经发送数据的大小
bytes_written_ += num_bytes;
//如果已经发送数据的大小
if(bytes_to_write_ > 0){
//每次发送payload_size_大小的数据,这里设置为64Kb,如果剩余的数据不足64KB就发发送剩余数据的大小
out_block_ = local_file_->read(qMin(bytes_to_write_, payload_size_));
//发送完一次数据后还剩余数据的大小
bytes_to_write_ -= tcp_client_->write(out_block_);
//清空发送缓存区
out_block_.resize(0);
}else{
//如果没有发送任何数据,则关闭文件
local_file_->close();
}
//更新进度
qDebug() << bytes_written_/total_bytes_ << "iiiii";
//如果发送文件成功
if(bytes_written_ == total_bytes_){
qDebug() << QString::fromLocal8Bit("传送文件成功");
local_file_->close();
tcp_client_->close();
}
}
void MainWindow::displayError(QAbstractSocket::SocketError)
{
qDebug() << tcp_client_->errorString();
tcp_client_->close();
}