Qt 使用TCP传输文件

  • Post author:
  • Post category:其他




传输流程

利用Sokcet通信中TCP进行文件的传输,可以分为两个模块:分别是服务端以及客户端。

大致流程则是在服务端中发送相应的文件,客户端则负责接收。

具体如下:

先通过通信将服务端与客户端连接,在客户端中通过相应的ip地址以及设定的端口port去获取与服务端的连接。而在服务端监听到相应的客户端时,则可成功连接,完成通信。此时则可以通过相应路径选择相应的文件进行发送。而客户端可以通过接收到的文件信息,将之分为文件名以及文件大小等相应信息去创建一个相同的文件,从而实现文件的传输。



代码说明

在服务端中主要是选择文件和发送文件,具体如下说明:

先对服务端窗口进行布局。

    this -> resize(300,300);
    this -> move(900,400);
    this -> setWindowTitle(QString::fromLocal8Bit("服务器"));
    SendBtn = new QPushButton("sendfile",this);
    ChooseBtn = new QPushButton("choosefile",this);
    p_TextEdit = new QTextEdit(this);
    QLabel *TextLabel = new QLabel(QString::fromLocal8Bit("服务器"), this);
    QGridLayout *ServerLayout = new QGridLayout(this);

    ServerLayout -> addWidget(SendBtn,4,0,1,1);
    ServerLayout -> addWidget(ChooseBtn,4,3,1,1);
    ServerLayout -> addWidget(p_TextEdit,1,0,1,4);
    ServerLayout -> addWidget(TextLabel,0,2,1,1,Qt::AlignCenter);//设置服务端的布局
    
    //将选择按钮设置成可点击,发送按钮不可点击。
    SendBtn ->setEnabled(false);
    ChooseBtn ->setEnabled(true);

    p_TcpServer = new QTcpServer(this);
    p_TcpSocket = new QTcpSocket(this);
    p_TcpServer -> listen(QHostAddress::Any,8888);//监听客户端
    connect(p_TcpServer,SIGNAL(newConnection()),this,SLOT(getConnect()));//连接成功则进入getConnect函数。
    connect(&timer,SIGNAL(timeout()),this,SLOT(sendData()));//设置定时器信号与槽
    connect(p_TcpSocket,SIGNAL(readyRead()),this,SLOT(readData()));

连接成功后则可以进行文件的选择,选择完成后就可以将文件发送。

void ServerWidget::getConnect()
{
    p_TcpSocket = p_TcpServer -> nextPendingConnection();
    QString ip = p_TcpSocket -> peerAddress().toString();
    quint16 port = p_TcpSocket -> peerPort();
    QString str = QString("[%1:%2] Connected").arg(ip).arg(port);
    p_TextEdit -> setText(str);

    connect(ChooseBtn,SIGNAL(clicked()),this,SLOT(chooseFile()));

}

void ServerWidget::chooseFile()
{
    QString FilePath = QFileDialog::getOpenFileName(this,"open","C:/Users/MSI-NB/Desktop/test/");//获取文件的路径。
    //打开文件
    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()<< "open error!";
        }
        p_TextEdit -> append(FilePath);
        SendBtn -> setEnabled(true);
        ChooseBtn -> setEnabled(false);//文件选择完成后则将choose按钮设置成不可点击而send按钮为可点击
        connect(SendBtn,SIGNAL(clicked()),this,SLOT(sendFile()));
    }
        else
        {
            qDebug()<< "filepath is error";

        }

}

在点击了send按钮进行文件的发送后,则可以进入sendFile函数进行文件的发送:

在发送文件时有时会产生黏包情况,其形成原因有可能是因为发送文件的时间间隔相对较短,后面的信息会与前面的信息连在一起,影响对文件的阅读。而这种由于时间间隔较短而产生的黏包,则可以通过使用定时器来延长时间间隔,从而避免黏包。

void ServerWidget::sendFile()
{
//设置文件的头部信息。
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    qint64 len = p_TcpSocket->write(head.toUtf8());
    if(len > 0)
    {
        timer.start(20);//将定时器开启从而可以防止文件黏包。
    }
    else
    {
        qDebug()<<"send headfile error!";
        file.close();
        SendBtn -> setEnabled(false);
        ChooseBtn -> setEnabled(true);
    }

}

而在客户端中主要则是申请连接服务端并接收文件:

首先先是对客户端窗口进行布局。

ClientWidget::ClientWidget(QWidget *parent) : QWidget(parent)
{
    this -> resize(300,300);
    this -> move(550,400);
    this -> setWindowTitle(QString::fromLocal8Bit("客户端"));
    is_start =true;
    connectBtn = new QPushButton("connect",this);
    QLabel *ipLabel = new QLabel("ip:",this);
    QLabel *portLabel = new QLabel("port:",this);
    ipEdit = new QLineEdit("127.0.0.1",this);
    portEdit = new QLineEdit("8888",this);
    textEdit = new QTextEdit(this);
    QGridLayout *ClientLayout = new QGridLayout(this);

    ClientLayout -> addWidget(connectBtn,0,4,2,1,Qt::AlignCenter);
    ClientLayout -> addWidget(ipLabel,1,0,1,1);
    ClientLayout -> addWidget(portLabel,0,0,1,1);
    ClientLayout -> addWidget(portEdit,0,1,1,3);
    ClientLayout -> addWidget(ipEdit,1,1,1,3);
    ClientLayout -> addWidget(textEdit,2,0,1,5);
    textEdit -> setReadOnly(true);

    p_TcpSocket = new QTcpSocket(this);
    connect(connectBtn,SIGNAL(clicked()),this,SLOT(getConnect()));
    connect(p_TcpSocket,SIGNAL(readyRead()),this,SLOT(recvData()));
}

在点击了connect按钮后进入getConnect函数连接服务器。

void ClientWidget::getConnect()
{
    QString ip = ipEdit ->text();
    quint16 port = portEdit -> text().toInt();
    p_TcpSocket -> connectToHost(QHostAddress(ip),port);
}

当与服务端连接成功后,接收服务端发送来的文件:

void ClientWidget::recvData()
{
    QByteArray buf = p_TcpSocket -> readAll();
    //若是头部文件则获取文件名以及文件大小,并创建文件。
    if(is_start == true)
    {
        is_start = false;
        fileName = QString(buf).section("##",0,0);
        fileSize = QString(buf).section("##",1,1).toInt();
        recvSize = 0;
        file.setFileName(fileName);
        file.open(QIODevice::WriteOnly);
//不是头部文件则直接读取其内部信息。
     else
       {
            qint64 len = file.write(buf);
            recvSize += len ;
            //当接收到数据的大小与文件大小相等时则关闭文件并弹窗说明。
            if(recvSize == fileSize)
            {
                file.close();
                QMessageBox::information(this,"Success","Success!!!!");
                textEdit -> setText("success!");
                p_TcpSocket -> disconnectFromHost();
                p_TcpSocket -> close();

            }
        }
}



版权声明:本文为weixin_38516302原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。