QT的network的使用

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

 

 只需要配置这个主机的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类来实现文本格式的数据传输。
  • 最后,我们需要在主函数中创建一个服务端对象和一个客户端对象,并尝试连接到服务端。如果连接成功,则从标准输入读取客户端的昵称,并存储在全局变量中。然后,进入一个无限循环,不断从标准输入读取数据,并发送给服务端,并接收服务端发送的数据,并打印到标准输出。😊

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Helloorld_11

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值