QT的network的使用

news2024/11/23 21:19:24

一个简单的双向的网络连接和信息发送。效果如下图所示:

 

 只需要配置这个主机的IP和端口号,由客户端发送链接请求。即可进行连接。

QT的network模块是一个用于网络编程的模块,它提供了一系列的类和函数,可以让您使用TCP/IP协议来创建客户端和服务端的应用程序。QT的network模块有以下几个特点:

  • 它支持多种网络协议,如HTTP、FTP、SMTP、POP3等,以及自定义的协议。
  • 它支持同步和异步的通信方式,可以根据您的需要选择合适的模式。
  • 它支持安全的通信,可以使用SSL/TLS协议来加密数据传输。
  • 它支持跨平台的开发,可以在Windows、Linux、MacOS等系统上运行。
  • 它支持移动设备的网络管理,可以检测和切换不同的网络接入点。

QT的network模块主要包括以下几类:

  • 网络访问API:这是一个用于处理高层次的网络操作的API,例如发送和接收HTTP请求和响应。它主要由QNetworkRequest、QNetworkAccessManager和QNetworkReply等类组成。
  • 套接字类:这是一些用于处理低层次的网络通信的类,例如使用TCP或UDP协议来发送和接收数据。它主要由QTcpSocket、QUdpSocket和QSslSocket等类组成。
  • 服务端类:这是一些用于创建网络服务端的类,例如监听指定端口并接受客户端连接。它主要由QTcpServer等类组成。
  • 网络代理类:这是一些用于通过代理服务器来过滤或转发网络流量的类。它主要由QNetworkProxy等类组成。这是一些用于通过代理服务器来过滤或转发网络流量的类。您可以使用QNetworkProxy等类来实现这种方式。这种方式的优点是可以增加网络通信的安全性和隐私性,以及避免一些网络限制或阻碍。这种方式的缺点是需要配置代理服务器的地址和端口号,以及可能影响网络通信的速度和稳定性。如果您想了解更多关于网络代理类的信息,您可以参考Network Programming with Qt | Qt Network 6.5.2中的Support for Network Proxies部分。
  • 承载管理API:这是一个用于管理移动设备上的网络连接状态的API,例如检测网络是否可用或切换不同的网络接入点。它主要由QNetworkConfigurationManager等类组成。

这里是官方文档的链接地址:Qt Network 6.5.2

首先要在pro文件里面包含下面的network,不然会报错

QT       += core gui network

然后再包含相关的头文件,比如:#include <QtNetwork>//包含头文件

咱们首先放上,这个客户端的头文件的代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetwork>//包含头文件
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;
    QTcpSocket *tcpSocket;
    QFile *localFile;  //要发送的文件
    qint64 totalBytes;  //数据总大小
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QString fileName;  //保存文件路径
    QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据
    QByteArray inBlock;   //数据缓冲区,接收
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息
private slots:
    void newConnect(); //连接服务器
    void readData();  //接收数据
    void sendData();//发送数据
    void continueSend(qint64 numBytes); //更新发送进度条
    void on_conBtn_clicked();
    void on_sendbtn_clicked();
};

#endif // WIDGET_H

然后再放上客户端的.cpp文件,代码部分如下:

#include "widget.h"
#include "ui_widget.h"
#include<QImageReader>
#include<QFileDialog>
#include<QDataStream>

//#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
//#endif

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);//建立UI界面
    tcpSocket = new QTcpSocket(this);
    //对变量参数进行初始化。
    loadSize = 4*1024;//每次发送数据大小
    totalBytes = 0;//总数据大小
    bytesWritten = 0;
    bytesToWrite = 0;
    //接收
    bytesReceived = 0;//已收到数据大小信息
    fileNameSize = 0;//文件大小信息
    //当有数据发送成功时,继续发送
    connect(tcpSocket,SIGNAL(bytesWritten(qint64)),this,
           SLOT(continueSend(qint64)));
    //接收数据
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readData()));
    ui->sendbtn->setEnabled(false);
}

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

void Widget::newConnect()
{
  //  blockSize = 0; //初始化其为0
    tcpSocket->abort(); //取消已有的连接
    //连接到主机,这里从界面获取主机地址和端口号
    tcpSocket->connectToHost(ui->hostEdit->text(), ui->portEdit->text().toInt());
    ui->sendbtn->setEnabled(true);//允许button可以进行点击
}

void Widget::readData()
{
    QDataStream in(tcpSocket);//定义发送方
    in.setVersion(QDataStream::Qt_5_8);
    if(bytesReceived <= sizeof(qint64)*2)
      { //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息
         if((tcpSocket->bytesAvailable() >= sizeof(qint64)*2)
               && (fileNameSize == 0))
           { //接收数据总大小信息和文件名大小信息
               in >> totalBytes >> fileNameSize;
               bytesReceived += sizeof(qint64) * 2;
           }
           if((tcpSocket->bytesAvailable() >= fileNameSize)
               && (fileNameSize != 0))
           {  //接收文件名,并建立文件
               in >> fileName;
              ui->statuslab->setText(tr("接收文件 %1 ...").arg(fileName));
               bytesReceived += fileNameSize;
               localFile= new QFile(fileName);
               if(!localFile->open(QFile::WriteOnly))
               {
                    qDebug() << "open file error!";
                    return;
               }
           }
           else return;
       }
       if(bytesReceived < totalBytes)
       {  //如果接收的数据小于总数据,那么写入文件
          bytesReceived += tcpSocket->bytesAvailable();
          inBlock+= tcpSocket->readAll();
       }
    //更新进度条
       ui->progressBar->setMaximum(totalBytes);
       ui->progressBar->setValue(bytesReceived);

       if(bytesReceived == totalBytes)
       { //接收数据完成时
           //接收显示
           QBuffer buffer(&inBlock);
           buffer.open(QIODevice::ReadOnly);
           QImageReader reader(&buffer,"jpg");
           QImage image = reader.read();
           if(!image.isNull())
           {
               image=image.scaled(ui->recLab->size());
               ui->recLab->setPixmap(QPixmap::fromImage(image));
           }
        localFile->write(inBlock);
        localFile->close();
        inBlock.resize(0);
        //重新置0 准备下次接收
        totalBytes = 0;
        bytesReceived = 0;
        fileNameSize = 0;
    ui->statuslab->setText(tr("接收文件 %1 成功!").arg(fileName));
       }
}

void Widget::sendData()
{
   bytesWritten = 0;
   fileName = QFileDialog::getOpenFileName(this);
   if(!fileName.isEmpty())
     {
       localFile = new QFile(fileName);
           if(!localFile->open(QFile::ReadOnly))
           {
              qDebug() << "open file error!";
              return;
           }

           //文件总大小
           totalBytes = localFile->size();
           QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
           sendOut.setVersion(QDataStream::Qt_5_8);
           QString currentFileName = fileName.right(fileName.size()
       - fileName.lastIndexOf('/')-1);

           //依次写入总大小信息空间,文件名大小信息空间,文件名
           sendOut << qint64(0) << qint64(0) << currentFileName;

           //这里的总大小是文件名大小等信息和实际文件大小的总和
           totalBytes += outBlock.size();

           sendOut.device()->seek(0);
           //返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
           sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));

           //发送完头数据后剩余数据的大小
           bytesToWrite = totalBytes - tcpSocket->write(outBlock);

           ui->statuslab->setText(tr("开始发送"));
           outBlock.resize(0);
     }

}

void Widget::continueSend(qint64 numBytes)
{
    //已经发送数据的大小
        bytesWritten += (int)numBytes;

        if(bytesToWrite > 0) //如果已经发送了数据
        {
       //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,
       //就发送剩余数据的大小
           outBlock = localFile->read(qMin(bytesToWrite,loadSize));

           //发送完一次数据后还剩余数据的大小
           bytesToWrite -= (int)tcpSocket->write(outBlock);

           //清空发送缓冲区
           outBlock.resize(0);

        } else {
           localFile->close(); //如果没有发送任何数据,则关闭文件
        }

        //更新进度条
        ui->progressBar->setMaximum(totalBytes);
        ui->progressBar->setValue(bytesWritten);

        if(bytesWritten == totalBytes) //发送完毕
        {
         ui->statuslab->setText(tr("传送文件 %1 成功").arg(fileName));
           localFile->close();
        }
}

void Widget::on_conBtn_clicked()
{
    newConnect();
}

void Widget::on_sendbtn_clicked()
{
  sendData();
}

然后就是服务端的代码,具体代码实现部分如下:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QtNetWork>
namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

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

private:
    Ui::Widget *ui;
    QTcpServer *tcpServer;
    QTcpSocket *currentClient;
    qint64 totalBytes;  //存放总大小信息
    qint64 bytesReceived;  //已收到数据的大小
    qint64 fileNameSize;  //文件名的大小信息
    QString fileName;   //存放文件名
    QFile *localFile;   //本地文件
    QByteArray inBlock;   //数据缓冲区
    qint64 bytesWritten;  //已经发送数据大小
    qint64 bytesToWrite;   //剩余数据大小
    qint64 loadSize;   //每次发送数据的大小
    QByteArray outBlock;  //数据缓冲区,即存放每次要发送的数据
private slots:
    void NewConnection();
    void recMessage();
    void sendMessage();
    void disconnect();
    void continueSend(qint64);
    void on_sendButton_clicked();
};

#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QDataStream>
#include<QFileDialog>
#include<QImageReader>
#include<qdebug.h>
#include<QHostAddress>
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    totalBytes = 0;
    bytesReceived = 0;
    fileNameSize = 0;
    tcpServer = new QTcpServer(this);
    if(!tcpServer->listen(QHostAddress::Any,6666))
    {  //**本地主机的6666端口,如果出错就输出错误信息,并关闭
        ui->plainTextEdit->appendPlainText(tcpServer->errorString());
        close();
    }
    //连接信号和相应槽函数,有新的连接进入是需处理
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(NewConnection()));
    ui->sendButton->setEnabled(false);

    ui->plainTextEdit->appendPlainText(tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText(QString::number (tcpServer->serverPort()));
//    QList<QNetworkInterface>  nets = QNetworkInterface::allInterfaces();
//    int count=nets.count();   //接口的数量
//    int i = 0;
//    foreach(QNetworkInterface netinterface,nets)
//    {

//        qDebug()<<i<<netinterface.name()<<netinterface.hardwareAddress()<<netinterface.humanReadableName();   //接口名称及MAC地址,暂不清楚name方法和humanReadableName方法的区别
//        ui->plainTextEdit->appendPlainText(netinterface.humanReadableName());
//        //判断该接口是否是环回口
//        QNetworkInterface::InterfaceFlags flags = nets[i].flags();
//        if(flags.testFlag(QNetworkInterface::IsLoopBack)){
//            qDebug()<<"This is loopback";
//        }
//        else {
//            qDebug()<<"This is not loopback";
//        }

//        i++;
//    }
//    QList<QHostAddress> list = QNetworkInterface::allAddresses();

//    for (int i = 0; i < list.size(); i++){
//        qDebug()<<i<<"     "<< list.at(i);
//        ui->plainTextEdit->appendPlainText(list.at(i).toString());
//    }

}

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

void Widget::NewConnection()
{
    //初始化为0;
    //blockSize=0;
   // inBlock.resize(0);
    //新连接进入的显示处理
    currentClient = tcpServer->nextPendingConnection();
    ui->statuslab->setText(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1])\
                                              .arg(currentClient->peerPort()));
    connect(currentClient, SIGNAL(readyRead()), this, SLOT(recMessage()));
    connect(currentClient, SIGNAL(disconnected()), this, SLOT(disconnect()));
    //当有数据发送成功时,继续发送
    connect(currentClient,SIGNAL(bytesWritten(qint64)),this, SLOT(continueSend(qint64)));
    ui->sendButton->setEnabled(true);
    /*调试***************************/
    //接收客户端的链接请求
    QTcpSocket *client = tcpServer->nextPendingConnection();
    //获取对方的IP和端口
    QString ip =  currentClient->peerAddress().toString();
    quint16 port =  currentClient->peerPort();
    //打印或处理IP和端口
    qDebug() << "Client IP:" << ip << "Port:" << port;

}

void Widget::recMessage()
{
    QDataStream in(currentClient);
    in.setVersion(QDataStream::Qt_5_8);
    if(bytesReceived <= sizeof(qint64)*2)
      { //如果接收到的数据小于16个字节,那么是刚开始接收数据,我们保存到//来的头文件信息
         if((currentClient->bytesAvailable() >= sizeof(qint64)*2)
               && (fileNameSize == 0))
           { //接收数据总大小信息和文件名大小信息
               in >> totalBytes >> fileNameSize;
               bytesReceived += sizeof(qint64) * 2;
           }
           if((currentClient->bytesAvailable() >= fileNameSize)
               && (fileNameSize != 0))
           {  //接收文件名,并建立文件
               in >> fileName;
               ui->statuslab->setText(tr("接收文件 %1 ...").arg(fileName));
               bytesReceived += fileNameSize;
               ui->statuslab->setText(fileName);
               localFile= new QFile(fileName);
               if(!localFile->open(QFile::WriteOnly))
               {
                    qDebug() << "open file error!";
                    return;
               }
           }
           else return;
       }
       if(bytesReceived < totalBytes)
       {  //如果接收的数据小于总数据,那么写入文件
          bytesReceived += currentClient->bytesAvailable();
          inBlock+= currentClient->readAll();
       }
    //更新进度条
       ui->progressBar->setMaximum(totalBytes);
       ui->progressBar->setValue(bytesReceived);

       if(bytesReceived == totalBytes)
       { //接收数据完成时
           //接收显示
           QBuffer buffer(&inBlock);
           buffer.open(QIODevice::ReadOnly);
           QImageReader reader(&buffer,"jpg");
           QImage image = reader.read();
           if(!image.isNull())
           {
               image=image.scaled(ui->recLab->size());
               ui->recLab->setPixmap(QPixmap::fromImage(image));
           }
        localFile->write(inBlock);
        localFile->close();
        inBlock.resize(0);
        //重新置0 准备下次接收
        totalBytes = 0;
        bytesReceived = 0;
        fileNameSize = 0;
         ui->statuslab->setText(tr("接收文件 %1 成功!").arg(fileName));
       }
}

void Widget::sendMessage()
{
    bytesWritten = 0;
    fileName = QFileDialog::getOpenFileName(this);
    if(!fileName.isEmpty())
      {
        localFile = new QFile(fileName);
            if(!localFile->open(QFile::ReadOnly))
            {
               qDebug() << "open file error!";
               return;
            }

            //文件总大小
            totalBytes = localFile->size();
            QDataStream sendOut(&outBlock,QIODevice::WriteOnly);
            sendOut.setVersion(QDataStream::Qt_5_8);
            QString currentFileName = fileName.right(fileName.size()
        - fileName.lastIndexOf('/')-1);

            //依次写入总大小信息空间,文件名大小信息空间,文件名
            sendOut << qint64(0) << qint64(0) << currentFileName;

            //这里的总大小是文件名大小等信息和实际文件大小的总和
            totalBytes += outBlock.size();

            sendOut.device()->seek(0);
            //返回outBolock的开始,用实际的大小信息代替两个qint64(0)空间
            sendOut<<totalBytes<<qint64((outBlock.size() - sizeof(qint64)*2));

            //发送完头数据后剩余数据的大小
            bytesToWrite = totalBytes - currentClient->write(outBlock);

            ui->statuslab->setText(tr("开始发送"));
            outBlock.resize(0);
      }

 }

 void Widget::continueSend(qint64 numBytes)
 {
     //已经发送数据的大小
         bytesWritten += (int)numBytes;

         if(bytesToWrite > 0) //如果已经发送了数据
         {
        //每次发送loadSize大小的数据,这里设置为4KB,如果剩余的数据不足4KB,
        //就发送剩余数据的大小
            outBlock = localFile->read(qMin(bytesToWrite,loadSize));

            //发送完一次数据后还剩余数据的大小
            bytesToWrite -= (int)currentClient->write(outBlock);

            //清空发送缓冲区
            outBlock.resize(0);

         } else {
            localFile->close(); //如果没有发送任何数据,则关闭文件
         }

         //更新进度条
         ui->progressBar->setMaximum(totalBytes);
         ui->progressBar->setValue(bytesWritten);

         if(bytesWritten == totalBytes) //发送完毕
         {
          ui->statuslab->setText(tr("传送文件 %1 成功").arg(fileName));
            localFile->close();
         }
}

void Widget::disconnect()
{

}

void Widget::on_sendButton_clicked()
{
    //发送数据
    sendMessage();
}

**************************************************************************************************************

下面我们用另外一个例子来简单的演示😊如何使用QT的network模块做一个简单的服务端和客户端的开发。用于实现一个简单的聊天程序。你可以参考以下的代码和注释来了解其原理和步骤:

#include <QCoreApplication>
#include <QTcpServer>
#include <QTcpSocket>
#include <QTextStream>

// 定义一个服务端类,继承自QTcpServer
class ChatServer : public QTcpServer
{
    Q_OBJECT

public:
    // 构造函数,接受一个端口号作为参数
    ChatServer(quint16 port)
    {
        // 监听指定的端口号,等待客户端的连接请求
        if (!listen(QHostAddress::Any, port))
        {
            qFatal("Failed to listen on port %d", port);
        }
        // 打印监听成功的信息
        qDebug() << "Chat server started on port" << port;
    }

protected:
    // 重写虚函数incomingConnection,处理客户端的连接请求
    void incomingConnection(qintptr socketDescriptor) override
    {
        // 创建一个QTcpSocket对象,用于和客户端通信
        QTcpSocket *socket = new QTcpSocket(this);
        // 将QTcpSocket对象与指定的套接字描述符关联
        socket->setSocketDescriptor(socketDescriptor);
        // 将QTcpSocket对象添加到客户端列表中
        clients.append(socket);
        // 打印客户端连接成功的信息
        qDebug() << "Client connected:" << socket->peerAddress().toString();
        // 连接QTcpSocket对象的readyRead信号和服务器的sendData槽函数,用于接收和发送数据
        connect(socket, &QTcpSocket::readyRead, this, &ChatServer::sendData);
        // 连接QTcpSocket对象的disconnected信号和服务器的removeClient槽函数,用于处理客户端断开连接
        connect(socket, &QTcpSocket::disconnected, this, &ChatServer::removeClient);
    }

private slots:
    // 定义一个槽函数,用于接收客户端发送的数据,并转发给其他客户端
    void sendData()
    {
        // 获取发送数据的客户端对象
        QTcpSocket *sender = qobject_cast<QTcpSocket *>(QObject::sender());
        // 如果客户端对象为空,返回
        if (!sender) return;
        // 读取客户端发送的数据,并转换为文本格式
        QTextStream stream(sender);
        QString data = stream.readAll();
        // 打印接收到的数据
        qDebug() << "Received data:" << data;
        // 遍历客户端列表,将数据转发给其他客户端
        for (QTcpSocket *client : clients)
        {
            if (client != sender)
            {
                QTextStream stream(client);
                stream << data;
                stream.flush();
            }
        }
    }

    // 定义一个槽函数,用于处理客户端断开连接,并从客户端列表中移除
    void removeClient()
    {
        // 获取断开连接的客户端对象
        QTcpSocket *sender = qobject_cast<QTcpSocket *>(QObject::sender());
        // 如果客户端对象为空,返回
        if (!sender) return;
        // 打印客户端断开连接的信息
        qDebug() << "Client disconnected:" << sender->peerAddress().toString();
        // 从客户端列表中移除客户端对象
        clients.removeOne(sender);
        // 删除客户端对象
        sender->deleteLater();
    }

private:
    QList<QTcpSocket *> clients; // 存储客户端对象的列表
};

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    ChatServer server(1234); // 创建一个服务端对象,监听1234端口

    return app.exec();
}

#include "moc_chatserver.cpp"

客户端代码:

#include <QCoreApplication>
#include <QTcpSocket>
#include <QTextStream>

// 定义一个全局变量,存储客户端的昵称
QString g_name;

// 定义一个函数,用于从标准输入读取一行文本,并发送给服务端
void sendToServer(QTcpSocket *socket)
{
    // 从标准输入读取一行文本
    QTextStream input(stdin);
    QString line = input.readLine();
    // 如果文本为空,返回
    if (line.isEmpty()) return;
    // 在文本前加上客户端的昵称
    line = g_name + ": " + line;
    // 创建一个文本流,关联到套接字对象
    QTextStream output(socket);
    // 将文本写入到套接字对象,并刷新
    output << line << endl;
    output.flush();
}

// 定义一个函数,用于从服务端接收一行文本,并打印到标准输出
void receiveFromServer(QTcpSocket *socket)
{
    // 创建一个文本流,关联到套接字对象
    QTextStream input(socket);
    // 读取一行文本
    QString line = input.readLine();
    // 如果文本为空,返回
    if (line.isEmpty()) return;
    // 将文本打印到标准输出
    QTextStream output(stdout);
    output << line << endl;
}

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    // 创建一个QTcpSocket对象,用于和服务端通信
    QTcpSocket socket;

    // 连接QTcpSocket对象的connected信号和QCoreApplication的quit槽函数,用于在连接成功后退出事件循环
    QObject::connect(&socket, &QTcpSocket::connected, &app, &QCoreApplication::quit);

    // 尝试连接到服务端,指定地址和端口号
    socket.connectToHost("127.0.0.1", 1234);

    // 进入事件循环,等待连接成功或超时
    app.exec();

    // 检查连接状态,如果连接失败,打印错误信息并退出程序
    if (socket.state() != QAbstractSocket::ConnectedState)
    {
        qCritical("Failed to connect to server");
        return -1;
    }

    // 打印连接成功的信息
    qDebug() << "Connected to server";

    // 从标准输入读取客户端的昵称,并存储在全局变量中
    QTextStream input(stdin);
    qDebug() << "Enter your name:";
    g_name = input.readLine();

    // 连接QTcpSocket对象的readyRead信号和receiveFromServer函数,用于接收服务端发送的数据
    QObject::connect(&socket, &QTcpSocket::readyRead, &{ receiveFromServer(&socket); });

    // 进入一个无限循环,不断从标准输入读取数据,并发送给服务端
    while (true)
    {
        sendToServer(&socket);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
        app.processEvents();
        Sleep(100);
       }
}

这个代码的目的是使用QT的network模块做一个简单的服务端和客户端的开发,实现一个简单的聊天程序。具体的步骤和原理如下:

  • 首先,我们需要引用一些头文件和库,用于支持QT的网络编程和标准输入输出。例如,我们需要引用QCoreApplication、QTcpServer、QTcpSocket、QTextStream等类,以及Ws2_32.lib和Bthprops.lib等库。
  • 然后,我们需要定义一个服务端类,继承自QTcpServer类。这个类负责监听指定的端口号,等待客户端的连接请求,并处理客户端的数据发送和接收。我们需要重写虚函数incomingConnection,用于处理客户端的连接请求,并创建一个QTcpSocket对象,用于和客户端通信。我们还需要定义一些槽函数,用于接收客户端发送的数据,并转发给其他客户端,以及处理客户端断开连接,并从客户端列表中移除。我们还需要定义一个私有成员变量,用于存储客户端对象的列表。
  • 接着,我们需要定义一个全局变量,用于存储客户端的昵称。这个变量在客户端发送数据时会加在数据前面,用于区分不同的客户端。
  • 然后,我们需要定义一个回调函数,用于处理认证过程中的事件和输入密码。这个函数会根据不同的认证方法,显示相应的信息,并询问用户是否接受或输入密码。然后,根据用户的选择,创建一个认证响应结构体,并设置为正面或负面响应,并发送给远程设备。
  • 接着,我们需要定义一些函数,用于从标准输入读取一行文本,并发送给服务端,以及从服务端接收一行文本,并打印到标准输出。这些函数会使用QTextStream类来实现文本格式的数据传输。
  • 最后,我们需要在主函数中创建一个服务端对象和一个客户端对象,并尝试连接到服务端。如果连接成功,则从标准输入读取客户端的昵称,并存储在全局变量中。然后,进入一个无限循环,不断从标准输入读取数据,并发送给服务端,并接收服务端发送的数据,并打印到标准输出。😊

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/892178.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

pdf格式文件下载不预览,云存储的跨域解决

需求背景 后端接口中返回的是pdf文件路径比如&#xff1a; pdf文件路径 &#xff08;https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&#xff09; 前端适配是这样的 <ahref"https://wangzhendongsky.oss-cn-beijing.aliyuncs.com/wzd-test.pdf&…

Spring框架之AOP详解

目录 一、前言 1.1.Spring简介 1.2.使用Spring的优点 二、Spring之AOP详解 2.1.什么是AOP 2.2.AOP在Spring的作用 2.3.AOP案例讲解 三、AOP案例实操 3.0.代理小故事&#xff08;方便理解代理模式&#xff09; 3.1.代码演示 3.2.前置通知 3.3.后置通知 3.3.环绕通知…

聚观早报|俞敏洪东方甄选带货北京特产;京东物流上半年盈利

【聚观365】8月17日消息 俞敏洪东方甄选直播间带货北京特产 京东物流上半年实现盈利 百度CTO称大语言模型为人工智能带来曙光 腾讯控股第二季度盈利262亿元 2023中国家庭智慧大屏消费白皮书 俞敏洪东方甄选直播间带货北京特产 近日&#xff0c;东方甄选在北京平谷区开播&…

Linux:shell脚本:基础使用(5)《正则表达式-sed工具》

sed是一种流编辑器&#xff0c;它是文本处理中非常中的工具&#xff0c;能够完美的配合正则表达式使用&#xff0c;功能不同凡响。 处理时&#xff0c;把当前处理的行存储在临时缓冲区中&#xff0c;称为“模式空间”&#xff08;pattern space&#xff09;&#xff0c;接着用s…

数据库MySQL 创建表INSERT

创建表 常见数据类型(列类型) 列类型之整型 unsigned的用法 列类型之bit 二进制表示 bit&#xff08;8&#xff09;表示一个字节 列类型之小数 1.单精度float 双精度double 2.decimal 自定义 M为小数点前面有多少位 D是小数点后面有多少位 列类型之字符串 1.char( 字符 )…

实现简单的element-table的拖拽效果

第一步&#xff0c;先随便创建element表格 <el-table ref"dragTable" :data"tableData" style"width: 100%" border fit highlight-current-row><el-table-column label"日期" width"180"><template slot-sc…

element-Plus中el-menu菜单无法正常收缩解决方案

<el-menu :collapse"true">如图所示收缩之后&#xff0c;有子级的菜单还有箭头文字显示 从代码对比看层级就不太对了&#xff0c;嵌套错误了&#xff0c;正常下方官网的ul标签下直接是li&#xff0c;在自己的代码中&#xff0c;ul标签下是div标签&#xff0c;层…

爬虫工具的选择与使用:阐述Python爬虫优劣势

作为专业爬虫ip方案解决服务商&#xff0c;我们每天都面对着大量的数据采集任务需求。在众多的爬虫工具中&#xff0c;Python爬虫凭借其灵活性和功能强大而备受青睐。本文将为大家分享Python爬虫在市场上的优势与劣势&#xff0c;帮助你在爬虫业务中脱颖而出。 一、优势篇 灵活…

初试rabbitmq

rabbitmq的七种模式 Hello word 客户端引入依赖 <!--rabbitmq 依赖客户端--><dependency><groupId>com.rabbitmq</groupId><artifactId>amqp-client</artifactId><version>5.8.0</version></dependency> 生产者 imp…

相对于多进程,你真的知道为什么要使用多线程吗(C/C++多线程编程)

目录 前言 线程VS进程 POSIX线程库的使用 线程创建 线程等待 线程分离 线程状态 可结合态线程实例 分离态线程实例 线程退出 线程的同步与互斥 同步互斥的概念 互斥锁&#xff08;互斥&#xff09; 互斥锁的使用步骤 总结说明 信号量 信号量的使用步骤 条件变…

数据包如何游走于 Iptables 规则之间?

在前文《Linux路由三大件》中&#xff0c;我们提到了 iptables 可以修改数据包的特征从而影响其路由。这个功能无论是传统场景下的 防火墙&#xff0c;还是云原生场景下的 服务路由&#xff08;k8s service&#xff09;、网络策略(calico network policy) 等都有依赖。 虽然业…

7.逻辑结构VS物理结构

第四章 文件管理 7.逻辑结构VS物理结构 ​   fopen这个函数做的事情就是打开了“test.txt”这个文件&#xff0c;并且“w”说明是以“写”的方式打开的&#xff0c;以“写”的方式打开才能往这个文件里写入数据&#xff0c;如果文件打开了那么fp这个指针就可以指向和这个文件…

Eclipse如何设置快捷键

在eclopse设置注释行和取消注释行 // 打开eclipse&#xff0c;依次打开&#xff1a;Window -> Preferences -> General -> Key&#xff0c;

数据结构--关键路径

数据结构–关键路径 AOE⽹ 在 带权有向图 \color{red}带权有向图 带权有向图中&#xff0c;以 顶点表示事件 \color{red}顶点表示事件 顶点表示事件&#xff0c;以 有向边表示活动 \color{red}有向边表示活动 有向边表示活动&#xff0c;以 边上的权值表示完成该活动的开销 \…

HCIE--------------------------------------第一节OSPF快速收敛(OSPF与BGP联动)

一、OSPF快速收敛概述 OSPF快速收敛是为了提高路由的收敛速度而做的扩展特性&#xff0c;包括&#xff1a;PRC&#xff08;Partial Route Calculation&#xff0c;部分路由计算&#xff09;和智能定时器。 同时&#xff0c;OSPF支持故障恢复快速收敛&#xff0c;例如通过OSPF …

Linux Server 20.04 Qt5.14.2配置Jetson Orin Nano Developer Kit 交叉编译环境

最近公司给了我一块Jetson Orin Nano的板子&#xff0c;让我搭建交叉编译环境&#xff0c;所以有了下面的文章 一 :Qt5.14.2交叉编译环境安装 1.准备 1.1设备环境 1.1.1 Server: Ubuntu20.04: Qt 源码 5.14.2 Qt 软件 5.14.2 gcc 版本 9.4.0 g 版本 9.4.0 1.1.2 Jetson …

在 React 中获取数据的6种方法

一、前言 数据获取是任何 react 应用程序的核心方面。对于 React 开发人员来说&#xff0c;了解不同的数据获取方法以及哪些用例最适合他们很重要。 但首先&#xff0c;让我们了解 JavaScript Promises。 简而言之&#xff0c;promise 是一个 JavaScript 对象&#xff0c;它将…

openGauss学习笔记-42 openGauss 高级数据管理-触发器

文章目录 openGauss学习笔记-42 openGauss 高级数据管理-触发器42.1 语法格式42.2 参数说明42.3 示例 openGauss学习笔记-42 openGauss 高级数据管理-触发器 触发器会在指定的数据库事件发生时自动执行函数。 42.1 语法格式 创建触发器 CREATE TRIGGER trigger_name { BEFORE…

Java8实战-总结16

Java8实战-总结16 引入流流与集合只能遍历一次外部迭代与内部迭代 引入流 流与集合 只能遍历一次 和迭代器类似&#xff0c;流只能遍历一次。遍历完之后&#xff0c;这个流就已经被消费掉了。可以从原始数据源那里再获得一个新的流来重新遍历一遍&#xff0c;就像迭代器一样…

使用qsqlmysql操作mysql提示Driver not loaded

环境: win10 IDE: qt creator 编译器: mingw32 这里简单的记录下。我遇到的情况是在IDE使用debug和release程序都是运行正常&#xff0c;但是当我编译成发布版本之后。老是提示Driver not load。 这就很奇诡了。 回顾了下编译的时候是需要在使用qt先编译下libqsqlmysql.dll的…