QT学习笔记17Socket通信

Qt中提供的所有的Socket类都是非阻塞的。

Qt中常用的用于socket通信的套接字类:

  • QTcpServer

    用于TCP/IP通信, 作为服务器端套接字使用

  • QTcpSocket

    用于TCP/IP通信,作为客户端套接字使用。

  • QUdpSocket

    用于UDP通信,服务器,客户端均使用此套接字。

1 TCP/IP


传统TCP通信过程:

QT学习笔记17Socket通信_第1张图片

在Qt中实现TCP/IP服务器端通信的流程:

  • 创建套接字
  • 将套接字设置为监听模式
  • 等待并接受客户端请求

    可以通过QTcpServer提供的void    newConnection()信号来检测是否有连接请求,如果有可以在对应的槽函数中调用nextPendingConnection函数获取到客户端的Socket信息(返回值为QTcpSocket*类型指针),通过此套接字与客户端之间进行通信。

  • 接收或者向客户端发送数据
    • 接收数据:使用read()或者readAll()函数
    • 发送数据:使用write()函数

客户端通信流程:

  • 创建套接字
  • 连接服务器

    可以使用QTcpSocket类的connectToHost()函数来连接服务器。

  • 向服务器发送或者接受数据

下面例子为简单的TCP/IP通信的实现:


QT学习笔记17Socket通信_第2张图片

服务器端

通过Qt提供的QTcpServer类实现服务器端的socket通信:

//---------- tcpserver.h ------------

class TCPServer : public QMainWindow

{

Q_OBJECT

 

public:

explicit TCPServer(QWidget *parent = 0);

~TCPServer();

 

public slots:

void slotNewConnection();

void slotReadyRead();

 

private:

Ui::TCPServer *ui;

// 负责监听的套接字

QTcpServer* m_server;

// 负责通信的套接字

QTcpSocket* m_client;

};

 

//---------- tcpserver.cpp ------------

TCPServer::TCPServer(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::TCPServer),

m_server(NULL),

m_client(NULL)

{

ui->setupUi(this);

 

//创建套接字对象

m_server = new QTcpServer(this);

//将套接字设置为监听模式

m_server->listen(QHostAddress::Any, 9999);

 

//通过信号接收客户端请求

connect(m_server, &QTcpServer::newConnection,

this, &TCPServer::slotNewConnection);

}

 

TCPServer::~TCPServer()

{

delete ui;

}

 

void TCPServer::slotNewConnection()

{

if(m_client == NULL)

{

//处理客户端的连接请求

m_client = m_server->nextPendingConnection();

//发送数据

m_client->write("服务器连接成功!!!");

//连接信号, 接收客户端数据

connect(m_client, &QTcpSocket::readyRead,

this, &TCPServer::slotReadyRead);

}

}

 

void TCPServer::slotReadyRead()

{

//接收数据

QByteArray array = m_client->readAll();

QMessageBox::information(this, "Client Message", array);

}

客户端

客户端通过使用Qt提供的QTcpSocket类可以方便的实现与服务器端的通信。

//------------- tcpclient.h ------------

class TCPClient : public QMainWindow

{

Q_OBJECT

 

public:

explicit TCPClient(QWidget *parent = 0);

~TCPClient();

 

public slots:

void slotReadyRead();

void slotSendMsg();

 

private:

Ui::TCPClient *ui;

QTcpSocket* m_client;

};

 

//------------- tcpclient.cpp --------------

TCPClient::TCPClient(QWidget *parent) :

QMainWindow(parent),

ui(new Ui::TCPClient)

{

ui->setupUi(this);

//创建套接字

m_client = new QTcpSocket(this);

//连接服务器

m_client->connectToHost(QHostAddress("127.0.0.1"), 9999);

 

//通过信号接收服务器数据

connect(m_client, &QTcpSocket::readyRead,

this, &TCPClient::slotReadyRead);

//发送按钮

connect(ui->btnSend, &QPushButton::clicked,

this, &TCPClient::slotSendMsg);

}

 

TCPClient::~TCPClient()

{

delete ui;

}

 

void TCPClient::slotReadyRead()

{

     //接收数据

QByteArray array = m_client->readAll();

QMessageBox::information(this, "Server Message", array);

}

 

void TCPClient::slotSendMsg()

{

QString text = ui->textEdit->toPlainText();

     //发送数据

m_client->write(text.toUtf8());

ui->textEdit->clear();

}

综合示例:

客户端:

头文件

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include 
#include  //通信套接字

namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_buttonConnect_clicked();

    void on_buttonSend_clicked();

    void on_buttonClose_clicked();

private:
    Ui::ClientWidget *ui;

    QTcpSocket *tcpSocket; //通信套接字
};

#endif // CLIENTWIDGET_H



实现文件


#include "clientwidget.h"
#include "ui_clientwidget.h"
#include 

ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);

    tcpSocket = NULL;

    //分配空间,指定父对象
    tcpSocket = new QTcpSocket(this);

    setWindowTitle("客户端");


    connect(tcpSocket, &QTcpSocket::connected,
            [=]()
            {
                ui->textEditRead->setText("成功和服务器建立好连接");
            }
            );

    connect(tcpSocket, &QTcpSocket::readyRead,
            [=]()
            {
                //获取对方发送的内容
                QByteArray array = tcpSocket->readAll();
                //追加到编辑区中
                ui->textEditRead->append(array);
            }

            );

}

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

void ClientWidget::on_buttonConnect_clicked()
{
    //获取服务器ip和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();

    //主动和服务器建立连接
    tcpSocket->connectToHost(QHostAddress(ip), port);

}

void ClientWidget::on_buttonSend_clicked()
{
    //获取编辑框内容
    QString str = ui->textEditWrite->toPlainText();
    //发送数据
    tcpSocket->write( str.toUtf8().data() );

}

void ClientWidget::on_buttonClose_clicked()
{
    //主动和对方断开连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
}



服务器:

头文件

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include 
#include  //监听套接字
#include  //通信套接字

namespace Ui {
class ServerWidget;
}

class ServerWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ServerWidget(QWidget *parent = 0);
    ~ServerWidget();

private slots:
    void on_buttonSend_clicked();

    void on_buttonClose_clicked();

private:
    Ui::ServerWidget *ui;

    QTcpServer *tcpServer; //监听套接字
    QTcpSocket *tcpSocket; //通信套接字

};

#endif // SERVERWIDGET_H


实现文件

#include "serverwidget.h"
#include "ui_serverwidget.h"

ServerWidget::ServerWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ServerWidget)
{
    ui->setupUi(this);

    tcpServer = NULL;
    tcpSocket = NULL;

    //监听套接字,指定父对象,让其自动回收空间
    tcpServer = new QTcpServer(this);

    tcpServer->listen(QHostAddress::Any, 8888);

    setWindowTitle("服务器: 8888");

    connect(tcpServer, &QTcpServer::newConnection,
            [=]()
            {
                //取出建立好连接的套接字
                tcpSocket = tcpServer->nextPendingConnection();

                //获取对方的IP和端口
                QString ip = tcpSocket->peerAddress().toString();
                qint16 port = tcpSocket->peerPort();
                QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);

                ui->textEditRead->setText(temp);

                connect(tcpSocket, &QTcpSocket::readyRead,
                        [=]()
                        {
                            //从通信套接字中取出内容
                            QByteArray array = tcpSocket->readAll();
                            ui->textEditRead->append(array);
                        }

                        );


            }

            );

}

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

void ServerWidget::on_buttonSend_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }
    //获取编辑区内容
    QString str = ui->textEditWrite->toPlainText();
    //给对方发送数据, 使用套接字是tcpSocket
    tcpSocket->write( str.toUtf8().data() );

}

void ServerWidget::on_buttonClose_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }

    //主动和客户端端口连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
    tcpSocket = NULL;
}




2 UDP

使用Qt提供的QUdpSocketQUdpSocket进行UDP通信。在UDP方式下,客户端并不与服务器建立连接,它只负责调用发送函数向服务器发送数据。类似的服务器也不从客户端接收连接,只负责调用接收函数,等待来自客户端的数据的到达



传统UDP通信过程:


QT学习笔记17Socket通信_第3张图片


在UDP通信中,服务器端和客户端的概念已经显得有些淡化,两部分做的工作都大致相同:

  • 创建套接字
  • 绑定套接字

    在UDP中如果需要接收数据需要对套接字进行绑定,只发送数据则不需要对套接字进行绑定。

    通过调用bind()函数将套接字绑定到指定端口上。

  • 接收或者发送数据
    • 接收数据:使用readDatagram()接收数据,函数声明如下:

      qint64    readDatagram(char * data, qint64 maxSize,

      QHostAddress * address = 0, quint16 * port = 0)

        参数:

  • data: 接收数据的缓存地址
  • maxSize: 缓存接收的最大字节数
  • address: 数据发送方的地址(一般使用提供的默认值)
  • port: 数据发送方的端口号(一般使用提供的默认值)

QT中的UDP通信过程


QT学习笔记17Socket通信_第4张图片


使用pendingDatagramSize()可以获取到将要接收的数据的大小,根据该函数返回值来准备对应大小的内存空间存放将要接收的数据。

  • 发送数据: 使用writeDatagram()函数发送数据,函数声明如下:

    qint64    writeDatagram(const QByteArray & datagram,

    const QHostAddress & host, quint16 port)

        参数:

  • datagram:要发送的字符串
  • host:数据接收方的地址
  • port:数据接收方的端口号


头文件

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include  //UDP套接字

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

    void dealMsg(); //槽函数,处理对方发过来的数据

private slots:
    void on_buttonSend_clicked();

private:
    Ui::Widget *ui;

    QUdpSocket *udpSocket; //UDP套接字
};

#endif // WIDGET_H



实现文件

#include "widget.h"
#include "ui_widget.h"
#include 

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //分配空间,指定父对象
    udpSocket = new QUdpSocket(this);

    //绑定
    //udpSocket->bind(8888);
    udpSocket->bind(QHostAddress::AnyIPv4, 8888);

    //加入某个组播
    //组播地址是D类地址
    udpSocket->joinMulticastGroup( QHostAddress("224.0.0.2") );
    //udpSocket->leaveMulticastGroup(); //退出组播

    setWindowTitle("服务器端口为:8888");

    //当对方成功发送数据过来
    //自动触发 readyRead()
    connect(udpSocket, &QUdpSocket::readyRead, this, &Widget::dealMsg);
}

void Widget::dealMsg()
{
    //读取对方发送的内容
    char buf[1024] = {0};
    QHostAddress cliAddr; //对方地址
    quint16 port;    //对方端口
    qint64 len = udpSocket->readDatagram(buf, sizeof(buf), &cliAddr, &port);
    if(len > 0)
    {
        //格式化 [192.68.2.2:8888]aaaa
        QString str = QString("[%1:%2] %3")
                .arg(cliAddr.toString())
                .arg(port)
                .arg(buf);
        //给编辑区设置内容
        ui->textEdit->setText(str);
    }


}

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

//发送按钮
void Widget::on_buttonSend_clicked()
{
    //先获取对方的IP和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();

    //获取编辑区内容
    QString str = ui->textEdit->toPlainText();

    //给指定的IP发送数据
    udpSocket->writeDatagram(str.toUtf8(), QHostAddress(ip), port);


}



定时器示例

头文件

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include  //定时器对象

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = 0);
    ~Widget();

private slots:
    void on_buttonStart_clicked();

    void on_buttonStop_clicked();

private:
    Ui::Widget *ui;

    QTimer *myTimer; //定时器对象
    int i;
};

#endif // WIDGET_H



实现文件
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    myTimer = new QTimer(this);
    i = 0;

    connect(myTimer, &QTimer::timeout,
            [=]()
            {
                i++;
                ui->lcdNumber->display(i);
            }

            );


}

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

void Widget::on_buttonStart_clicked()
{
    //启动定时器
    //时间间隔为100ms
    //每隔100ms,定时器myTimer自动触发timeout()
    //如果定时器没有激活,才启动
    if(myTimer->isActive() == false)
    {
         myTimer->start(100);
    }

}

void Widget::on_buttonStop_clicked()
{
    if(true == myTimer->isActive())
    {
        myTimer->stop();
        i = 0;
    }
}





广播

在使用QUdpSocket类的writeDatagram()函数发送数据的时候,其中第二个参数host应该指定为广播地址:QHostAddress::Broadcast此设置相当于QHostAddress("255.255.255.255")

使用UDP广播的的特点:

  • 使用UDP进行广播,局域网内的其他的UDP用户全部可以收到广播的消息
  • UDP广播只能在局域网范围内使用

组播

我们再使用广播发送消息的时候会发送给所有用户,但是有些用户是不想接受消息的,这时候我们就应该使用组播,接收方只有先注册到组播地址中才能收到组播消息,否则则接受不到消息。另外组播是可以在Internet中使用的。

在使用QUdpSocket类的writeDatagram()函数发送数据的时候,其中第二个参数host应该指定为组播地址,关于组播地址的分类:

  • 224.0.0.0~224.0.0.255为预留的组播地址(永久组地址),地址224.0.0.0保留不做分配,其它地址供路由协议使用;
  • 224.0.1.0~224.0.1.255是公用组播地址,可以用于Internet;
  • 224.0.2.0~238.255.255.255为用户可用的组播地址(临时组地址),全网范围内有效;
  • 239.0.0.0~239.255.255.255为本地管理组播地址,仅在特定的本地范围内有效。

注册加入到组播地址需要使用QUdpSocket类的成员函数:

bool    joinMulticastGroup(const QHostAddress & groupAddress)

3 TCP/IP 和 UDP的区别
 

TCP/IP

UDP

是否连接

面向连接

无连接

传输方式

基于流

基于数据报

传输可靠性

可靠

不可靠

传输效率

效率低

效率高

能否广播

不能


TCP传送文件


QT学习笔记17Socket通信_第5张图片





用一个应用程序进行测试(发送接收都是同一个程序):


主体框架:

#include "serverwidget.h"
#include 
#include "clientwidget.h"

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    ServerWidget w;
    w.show();

    ClientWidget w2;
    w2.show();

    return a.exec();
}



客户端

头文件

#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include 
#include 
#include 

namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

public:
    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



实现文件

#include "clientwidget.h"
#include "ui_clientwidget.h"
#include 
#include 
#include 

ClientWidget::ClientWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ClientWidget)
{
    ui->setupUi(this);

    tcpSocket = new QTcpSocket(this);

    isStart = true;

    ui->progressBar->setValue(0); //当前值

    setWindowTitle("客户端");

    connect(tcpSocket, &QTcpSocket::connected,
    [=]()
    {
        //提示连接成功
        ui->textEdit->clear();
        ui->textEdit->append("和服务器连接成功,等待服务器传送文件……");
    }
    );

    connect(tcpSocket, &QTcpSocket::readyRead,
    [=]()
    {
        //取出接收的内容
        QByteArray buf = tcpSocket->readAll();

        if(true == isStart)
        {//接收头
            isStart = false;
            //解析头部信息 QString buf = "hello##1024"
            //                    QString str = "hello##1024#mike";
            //                            str.section("##", 0, 0)

            //初始化
            //文件名
            fileName = QString(buf).section("##", 0, 0);
            //文件大小
            fileSize = QString(buf).section("##", 1, 1).toInt();
            recvSize = 0;   //已经接收文件大小

            //打开文件
            //关联文件名字
            file.setFileName(fileName);

            //只写方式方式,打开文件
            bool isOk = file.open(QIODevice::WriteOnly);
            if(false == isOk)
            {
                qDebug() << "WriteOnly error 49";

                tcpSocket->disconnectFromHost(); //断开连接
                tcpSocket->close(); //关闭套接字

                return; //如果打开文件失败,中断函数
            }

            //弹出对话框,显示接收文件的信息
            QString str = QString("接收的文件: [%1: %2kb]").arg(fileName).arg(fileSize/1024);
            //QMessageBox::information(this, "文件信息", str);
            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) //接收数据大于0
            {
                recvSize += len; //累计接收大小
                qDebug() << len;
            }

            //更新进度条
            ui->progressBar->setValue(recvSize/1024);

            if(recvSize == fileSize) //文件接收完毕
            {

                //先给服务发送(接收文件完成的信息)
                tcpSocket->write("file done");

                ui->textEdit->append("文件接收完成");
                QMessageBox::information(this, "完成", "文件接收完成");
                file.close(); //关闭文件
                //断开连接
                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);
}



服务器

头文件

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include 
#include  //监听套接字
#include  //通信套接字
#include 
#include 

namespace Ui {
class ServerWidget;
}

class ServerWidget : public QWidget
{
    Q_OBJECT

public:
    explicit ServerWidget(QWidget *parent = 0);
    ~ServerWidget();

    void sendData(); //发送文件数据

private slots:
    void on_buttonFile_clicked();

    void on_buttonSend_clicked();

private:
    Ui::ServerWidget *ui;

    QTcpServer *tcpServer; //监听套接字
    QTcpSocket *tcpSocket; //通信套接字

    QFile file; //文件对象
    QString fileName; //文件名字
    qint64 fileSize; //文件大小
    qint64 sendSize; //已经发送文件的大小

    QTimer timer; //定时器





};

#endif // SERVERWIDGET_H



实现文件


#include "serverwidget.h"
#include "ui_serverwidget.h"
#include 
#include 
#include 

ServerWidget::ServerWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::ServerWidget)
{
    ui->setupUi(this);

    //监听套接字
    tcpServer = new QTcpServer(this);

    //监听
    tcpServer->listen(QHostAddress::Any, 8888);
    setWindowTitle("服务器端口为:8888");

    //两个按钮都不能按
    ui->buttonFile->setEnabled(false);
    ui->buttonSend->setEnabled(false);

    //如果客户端成功和服务器连接
    //tcpServer会自动触发 newConnection()
    connect(tcpServer, &QTcpServer::newConnection,
    [=]()
    {
        //取出建立好连接的套接字
        tcpSocket = tcpServer->nextPendingConnection();
        //获取对方的ip和端口
        QString ip = tcpSocket->peerAddress().toString();
        quint16 port = tcpSocket->peerPort();

        QString str = QString("[%1:%2] 成功连接").arg(ip).arg(port);
        ui->textEdit->setText(str); //显示到编辑区

        //成功连接后,才能按选择文件
        ui->buttonFile->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_buttonFile_clicked()
{
    QString filePath = QFileDialog::getOpenFileName(this, "open", "../");
    if(false == filePath.isEmpty()) //如果选择文件路径有效
    {
        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(false == isOk)
        {
            qDebug() << "只读方式打开文件失败 106";
        }

        //提示打开文件的路径
        ui->textEdit->append(filePath);

        ui->buttonFile->setEnabled(false);
        ui->buttonSend->setEnabled(true);

    }
    else
    {
        qDebug() << "选择文件路径出错 118";
    }

}
//发送文件按钮
void ServerWidget::on_buttonSend_clicked()
{
    ui->buttonSend->setEnabled(false);

    //先发送文件头信息  文件名##文件大小
    QString head = QString("%1##%2").arg(fileName).arg(fileSize);
    //发送头部信息
    qint64 len = tcpSocket->write( head.toUtf8() );
    if(len > 0)//头部信息发送成功
    {
        //发送真正的文件信息
        //防止TCP黏包
        //需要通过定时器延时 20 ms
        timer.start(20);


    }
    else
    {
        qDebug() << "头部信息发送失败 142";
        file.close();
        ui->buttonFile->setEnabled(true);
        ui->buttonSend->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;

     }while(len > 0);


//     //是否发送文件完毕
//     if(sendSize == fileSize)
//     {
//         ui->textEdit->append("文件发送完毕");
//         file.close();

//         //把客户端端口
//         tcpSocket->disconnectFromHost();
//         tcpSocket->close();
//     }


}


你可能感兴趣的:(QT)