美文网首页
TCP发送文件

TCP发送文件

作者: xqiiitan | 来源:发表于2025-05-07 11:44 被阅读0次

总结:

1.QFile file(name)
file.setFileName()
readAll()/readLine()----atEnd()==true,文件到结尾了
int size = write(char* buf, int size);
2.QTextStream ts(&f);
ts.setDevice(&f);
readAll()/ readLine()
ts << "abcdef"; // 将内容abcdeef,写入到ts中。
ts >> str; // 从设备中取内容,放到str中。
3.QDataStream ds(&f);
读文件:
ds >> str >> number;
写文件:
ds << str << number; // 读写的顺序,要保持一致。
4.QByteArray array;
QPixmap pix;
QDataStream ds(&array, QIODevice::WriteOnly);
ds << pix;
5.TCP,依赖模块是 qmake += network。
【服务器端】:
a.listen:QTcpServer-- 不是IO设备。父类是QObject。
b.通信:QTcpSocket--IO设备,父类是QIODevice *conn
- 服务器端监听,server.listen(Any, port);
- newConnection(); 接收请求,拿到client端的套接字对象的地址。
conn = server.nextPendingConnection();
- write()
- read()读数据,readyRead信号,表示数据来了。
【客户端】:QTcpSocket cl;
a. cl.connectToHost(IP, port); // 都是服务器的ip和port

// 获取客户端基本信息
QTcpSocket *ss;
ss = server.nextPendingConnection();
sockList.append(ss);
QString IP = ss->peerAddress().toString();
quint16 port = ss->peerPort();  

QList<QTcpSocket*> sockList; // tcp连接多个

6.UDP类:QUdpSocket--- io设备。

  • 发数据:s.writeDatagrame(data, 对方IP,对方Port)
  • readyRead()信号 去读数据
    quint64 size = s.pendingDatagrameSize();
    QByteArray array(size, 0); // 不要delete
    s.readDatagrame(array.data(), size);
  • udp接收数据:要绑定端口号(本地的)
  • 广播地址:255.255.255.255
  • 组播地址:好几个组播地址。 加入到组播地址joinMulticastGroup().

文件传输。

传输的时候,文件的大小和文件名先传输过去。
熊出没.avi##10000
当接收的字节数 == 文件的大小,代表文件接收完成了。
组装的头先发送,然后分块读取文件。
每收到一条数据,就往文件中写一条数据。

QString str;
str.section("##", 0,0) == 熊出没.avi
section("##", 0,1) == 熊出没 10000

1.服务器端

serverwidget.h
#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include <QMainWindow>
#include <QTcpServer> //network
#include <QTcpSocket>
#include <QFile>
#include <QTimer>

QT_BEGIN_NAMESPACE
namespace Ui { class ServerWidget; }
QT_END_NAMESPACE

class ServerWidget : public QMainWindow
{
    Q_OBJECT

public:
    ServerWidget(QWidget *parent = nullptr);
    ~ServerWidget();

private:
    void on_buttonChoose_clicked();
    void on_buttonSend_clicked();
    void sendFileData();

    Ui::ServerWidget *ui;
    QTcpServer* tcpServer; //监听的套接字
    QTcpSocket* tcpSocket;   //通信的套接字
    QTimer timer ; //定时器

    QString fileName = "";
    qint64  fileSize =0;
    qint64  sendSize =0;
    QFile file;
};
#endif // SERVERWIDGET_H
//https://www.cnblogs.com/lalala-lueluelue/p/12673764.html
serverwidget.cpp
#include "serverwidget.h"
#include "ui_serverwidget.h"
#include <QMessageBox>
#include <QTimer>
#include <QFileDialog>


ServerWidget::ServerWidget(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::ServerWidget)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer(this);
    bool isOk = tcpServer->listen(QHostAddress::Any, 8888);
    if(!isOk){ // listen failed
        QMessageBox::warning(this, "监听", "监听失败");
        return;
    }
    setWindowTitle("服务器:8888");
    ui->buttonChoose->setEnabled(false);
    ui->buttonSend->setEnabled(false);
    //当有客户端连接时,触发信号newConnection
    connect(tcpServer, &QTcpServer::newConnection, [=](){
        //
        tcpSocket = tcpServer->nextPendingConnection();
        QString ip = tcpSocket->peerAddress().toString();
        qint16 port = tcpSocket->peerPort();
        QString str = QString("[1%: 2%]和服务器连接成功").arg(ip).arg(port);

        ui->textEdit->setText(str);
        ui->buttonChoose->setEnabled(true);
        QMessageBox::information(this, "允许", "连接成功,可以选择文件发送。");
    });

    connect(&timer, &QTimer::timeout, [=](){
        this->timer.stop();
        sendFileData(); // send file data
    });
}

ServerWidget::~ServerWidget()
{
    delete ui;
}

// select file btn
void ServerWidget::on_buttonChoose_clicked()
{
    QString path = QFileDialog::getOpenFileName(this,"请选择所要发送的文件", "../");
    if(path.isEmpty() == false) { // 路径有效
        file.setFileName(path);
        bool isOk = file.open(QIODevice::ReadOnly);
        if(false==isOk) {
            QMessageBox::warning(this, "Warning", "Open file failed");
            return;
        }else {
            ui->textEdit->append("to send File:");
            ui->textEdit->append(path);
            // init data
            fileName = "";
            fileSize =0;
            sendSize =0;
            // 获取发送文件的信息
            QFileInfo info(path);
            fileName = info.fileName();
            fileSize = info.size();
            ui->buttonSend->setEnabled(true);
            ui->buttonChoose->setEnabled(false);
        }
    }
}

void ServerWidget::on_buttonSend_clicked()
{
    ui->buttonSend->setEnabled(false);
    QString buf = QString("head#%1#%2").arg(fileName).arg(fileSize);
    qint64 len = tcpSocket->write(buf.toUtf8().data());
    tcpSocket->waitForBytesWritten();//等待数据发送完毕

    ui->textEdit->append("已经在发送文件!!");
    if(len>0) {
        this->timer.start(1000);
        //delay avoid package rebuild.
    }else {
        file.close();
    }
}

void ServerWidget::sendFileData()
{
    qint64 len =0;
    do{
        char buf[2048] = {0};
        len = 0;
        len = file.read(buf, sizeof(buf)); // read data
        len = tcpSocket->write(buf,len);   // send data
        sendSize += len;
    }while(len >0);

    if(sendSize == fileSize)
    {
        ui->textEdit->append("文件发送完毕 ");
        file.close();
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
    }
}

2.client端

clientwidget.h
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QtNetwork> //network
#include <QFile>

namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ClientWidget(QWidget *parent = nullptr);
    ~ClientWidget();

private slots:
    void on_ButtonConnect_clicked();
private:
    Ui::ClientWidget *ui;

    QTcpSocket* tcpSocket;//通信套接字
    QFile file;//文件对象
    QString fileName = "";//文件名称,大小
    qint64 fileSize =0;//
    qint64 recvSize =0; //已接收文件的大小
    bool  isFile;//接收文件数据标志
};

#endif // CLIENTWIDGET_H

clientwidget.cpp
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QDebug>
#include <QMessageBox>

ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);
    //set tcp socket
    tcpSocket = new QTcpSocket(this);
    setWindowTitle("客户端");

    connect(tcpSocket, &QTcpSocket::connected, this, [=](){
        // init data
        fileName = "";
        fileSize =0;
        recvSize =0;
        isFile = false;

        ui->buttonConnect->setEnabled(false);
        ui->textEdit->clear();
        ui->textEdit->append("与服务器连接成功。");
    });
    ui->progressBar->setValue(0);

    // when have data to receive
    connect(tcpSocket, &QTcpSocket::readyRead, [=](){
        QByteArray buf = tcpSocket->readAll(); //全部读取进来
        if(false == isFile) { // 先接收头部信息 head
            isFile = true;
            //"head#fileName#fileSize" 截取字符串
            fileName = QString(buf).section("#", 1,1);
            fileSize = QString(buf).section("#", 2,2).toInt();
            qDebug() << fileName << fileSize;
            recvSize =0;

            file.setFileName(fileName);
            if(false == file.open(QIODevice::WriteOnly)){
                //init data
                fileName = "";
                fileSize =0;
                recvSize =0;
                isFile = false;
                QMessageBox::warning(this,"警告", "创建文件失败");
                return;
            }
            ui->progressBar->setMinimum(0);
            ui->progressBar->setMaximum(fileSize/1024);
            ui->textEdit->append("正在接收文件:\n");
            ui->textEdit->append(fileName);
        } else {
            // 文件数据,最重要的一部分
            qint64 len = file.write(buf);
            recvSize += len;
            qDebug() << len;
            ui->progressBar->setMaximum(recvSize/1024);
        }

        //文件接收完毕
        if(recvSize == fileSize) {
            file.close();
            ui->buttonConnect->setEnabled(true);
            tcpSocket->disconnectFromHost();
            QMessageBox::information(this,"ok", "File receive finished.");
            ui->textEdit->append("文件接收完毕");
        }
    });
}
ClientWidget::~ClientWidget()
{
    delete ui;
}

//连接按钮
void ClientWidget::on_ButtonConnect_clicked()
{
    ui->progressBar->setValue(0);
    QString ip = ui->lineEditIP->text();
    quint16 port = ui->lineEditPort->text().toInt();
    if(ip.isEmpty() || port==0) {
         QMessageBox::information(this,"警告", "ip/port can't be null.");
        return ;
    }
    tcpSocket->abort(); //取消已有的连接
    tcpSocket->connectToHost(QHostAddress(ip), port); //连接服务器
}
main.cpp
#include "serverwidget.h"
#include "clientwidget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ServerWidget w;
    w.show();

    ClientWidget cw;
    cw.show();
    return a.exec();
}

相关文章

  • Java 实现阻塞队列 Netty发送限流

    场景:项目使用Netty作为TCP客户端发送消息给TCP服务器出现了消息丢失问题(发送的是文件,按照规则分成几十个...

  • 【golang】实现基于TCP协议的文件传输

    利用tcp协议,建立发送端与接收端的连接,通过这个连接,以字节切片的形式,完成文件传输。 一、发送端 发送端主要步...

  • 网络知识点总结

    1、tcp如何保证传输的可靠性 合理分片:将数据分割成最适合tcp发送的数据块超时重传:tcp发送端发送数据后会启...

  • JAVA-每日一面 2022-01-25

    什么是 TCP 粘包/拆包以及TCP 粘包/拆包的解决办法 TCP 粘包/拆包1、要发送的数据大于 TCP 发送缓...

  • TCP协议入门

    (1)TCP特点 1.TCP是字节流服务。发送端应用程序执行写操作的数据先被放入TCP发送缓冲区中。当TCP模块开...

  • BDP

    带宽 * 网络延时 = 缓冲区大小 TCP往返传输时间(RTT)的估计 TCP传输往返时间是指发送端从发送TCP包...

  • java 网络编程之TCP “三次握⼿”

    TCP “三次握⼿”原理 每次握手(发送数据请求或应答)时,发送的数据为TCP报⽂,TCP段包含了源/目的地址,端...

  • netty学习系列一:Java NIO预备知识

    一、TCP发送缓冲区/TCP接收缓冲区 在传输层,每个socket对应的TCP连接都拥有自己的接收缓冲区和发送缓冲...

  • Java分析之TCP接收和发送数据

    前言 本文主要讲TCP板块,大致概括了一下TCP接收和发送数据的过程,写的比较简单,大家将就看昂。 TCP发送数据...

  • tcp粘包 go和swoole

    tcp 粘包及处理 go 和swoole tcp粘包形成的原因 tcp在发送和接收时会有个缓存,当短时间内发送大量...

网友评论

      本文标题:TCP发送文件

      本文链接:https://www.haomeiwen.com/subject/xcdrijtx.html