QT学习笔记17Socket通信

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

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

  • QTcpServer

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

  • QTcpSocket

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

  • QUdpSocket

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

1 TCP/IP


传统TCP通信过程:


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

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

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

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

客户端通信流程:

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

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

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

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



服务器端

通过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 <QWidget>
#include <QTcpSocket> //通信套接字

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 <QHostAddress>

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 <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字

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通信过程:




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

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

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

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

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

      qint64    readDatagram(char * data, qint64 maxSize,

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

        参数:

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

QT中的UDP通信过程




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

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

    qint64    writeDatagram(const QByteArray & datagram,

    const QHostAddress & host, quint16 port)

        参数:

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


头文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QUdpSocket> //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 <QHostAddress>

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 <QWidget>
#include <QTimer> //定时器对象

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传送文件







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


主体框架:

#include "serverwidget.h"
#include <QApplication>
#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 <QWidget>
#include <QTcpSocket>
#include <QFile>

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 <QDebug>
#include <QMessageBox>
#include <QHostAddress>

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 <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字
#include <QFile>
#include <QTimer>

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 <QFileDialog>
#include <QDebug>
#include <QFileInfo>

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();
//     }


}


  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: Qt 是一个跨平台的应用程序开发框架,采用 C++ 编写。DES(Data Encryption Standard)是一种对称加密算法,用于保护数据的机密性。 要在 Qt 中实现 DES 加密的 socket 通信,可以按照以下步骤进行: 1. 导入所需的库:包括 `QTcpSocket` 用于建立 socket 通信,`QDataStream` 用于数据的传输和序列化,以及 `QMessageBox` 用于显示错误信息。 2. 创建一个 `QTcpServer` 对象并监听指定的主机和端口。当有客户端连接时,`newConnection()` 信号将会触发。 3. 在 `newConnection()` 信号的槽函数中,通过 `nextPendingConnection()` 获取连接的套接字。然后,使用 `setSocketDescriptor()` 将套接字设置给一个 `QTcpSocket` 对象。 4. 在 `QTcpSocket` 的 `readyRead()` 信号的槽函数中,当套接字有数据可读时,将读取的数据保存,并进行解密操作。可以使用 DES 相关的库函数或者自行实现 DES 解密算法。 5. 在 `QTcpSocket` 的 `bytesWritten(qint64 bytes)` 信号的槽函数中,当数据成功写入套接字时,显示已发送的字节数。 6. 客户端发送数据时,使用 `QTcpSocket` 对象的 `write()` 函数将要发送的数据写入套接字,发送给服务器。 7. 最后,创建一个 `QTcpSocket` 对象并调用 `connectToHost()` 连接到服务器的主机和端口。 通过按照上述步骤实现,可以在 Qt 中实现 DES 加密的 socket 通信。 ### 回答2: Qt 是一个跨平台的应用程序框架,可以用来开发各种类型的应用程序,包括网络通信应用。而 DES(Data Encryption Standard)是一种对称加密算法,可以用来对数据进行加密和解密。 要在 Qt 中实现 DES 加密的 Socket 通信,可以按照以下步骤: 1. 导入 Qt 相关的网络通信类:在代码中导入 `QTcpSocket` 和 `QTcpServer` 类,这两个类提供了 TCP/IP socket 通信的功能。 2. 创建 TCP 服务器:使用 `QTcpServer` 类创建一个 TCP 服务器,并绑定到特定的 IP 地址和端口。 3. 监听客户端连接请求:在服务器端调用 `listen` 函数,开始监听客户端的连接请求。一旦有客户端请求连接,服务器将会触发 `newConnection` 信号。 4. 接受客户端连接:在 `newConnection` 信号的槽函数中,使用 `nextPendingConnection` 函数接受客户端的连接请求,并返回一个新的 `QTcpSocket` 对象,这个对象用于和客户端进行通信。 5. 实现 DES 加密算法:使用 DES 算法对需要传输的数据进行加密和解密。Qt 没有提供 DES 算法的实现,可以调用第三方的加密库,例如 OpenSSL。 6. 客户端发送加密数据:在客户端中创建一个 `QTcpSocket` 对象,并连接到服务器的 IP 地址和端口。然后,将需要传输的数据使用 DES 算法加密,并通过 `write` 函数将加密后的数据发送给服务器端。 7. 服务器端接收并解密数据:在服务器端的 `QTcpSocket` 对象中,使用 `readyRead` 信号和对应的槽函数,实现接收客户端发送的加密数据。然后,对接收到的数据使用 DES 算法进行解密,并处理解密后的数据。 8. 客户端接收服务器响应:在客户端中,使用 `readyRead` 信号和对应的槽函数,实现接收服务器端发送的响应。同样,对接收到的加密数据,使用 DES 算法进行解密,并处理解密后的数据。 通过以上步骤,就可以在 Qt 中实现 DES 加密的 Socket 通信。其中,需要注意的是实现 DES 加密算法的部分可能需要调用第三方的加密库来实现。 ### 回答3: Qt是一个跨平台的应用程序开发框架,可以用来实现各种各样的应用程序,包括加密通信。 DES(Data Encryption Standard)是一种对称密钥加密算法,可以用来对通信数据进行加密。在Qt中,可以使用QCryptographicHash类来实现DES加密。 首先,需要导入QCryptographicHash和QTcpSocket类库: #include <QCryptographicHash> #include <QTcpSocket> 接下来,创建一个QTcpSocket对象,并连接到服务器: QTcpSocket *socket = new QTcpSocket(); socket->connectToHost("服务器地址", 端口号); 然后,可以将待加密的数据转换为QByteArray类型,并使用QCryptographicHash类的hash()函数进行加密: QByteArray data = "需要加密的数据"; QCryptographicHash hash(QCryptographicHash::Md5); //选择加密算法为DES hash.addData(data); //将数据添加到加密算法中 QByteArray encrypted = hash.result().toHex(); //获取加密结果,并转换为16进制表示的ByteArray 最后,将加密后的数据发送给服务器: socket->write(encrypted); 在接收到服务器返回的数据后,可以使用同样的方法解密数据: QByteArray receivedData = socket->readAll(); QCryptographicHash decrypt(QCryptographicHash::Md5); decrypt.addData(receivedData); QByteArray decrypted = decrypt.result().toHex(); 这样就完成了使用Qt实现DES加密socket通信的过程。需要注意的是,这只是一种简单的示例,并没有考虑到网络安全性和加密解密的正确性,实际使用时需要根据具体的需求进行调整和完善。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值