Qt网络通信(服务端的实现)

参考up主:社长_嵌入式

一:学到的重点

1 serve->listen(host,8888)

主机的地址 QHostAddress host("192.168.26.5"); 8888设置主机的端口号

在 Qt 里,serve->listen() 通常是 QTcpServer 类对象调用 listen() 函数。QTcpServer 类的作用是创建一个 TCP 服务器,它可以监听特定的地址和端口,等待客户端的连接请求。

2 &QTcpServer::newConnection

newConnection:这是 QTcpServer 类中定义的一个信号。当有新的客户端连接到服务器时,QTcpServer 对象就会发出 newConnection 信号。

3 serve->hasPendingConnections()

  • 功能:调用 QTcpServer 类的 hasPendingConnections() 函数,用于检查服务器是否有等待处理的客户端连接请求。
  • 返回值:若存在待处理的连接,返回 true;反之则返回 false
  • 逻辑:若有等待处理的连接,执行 if 语句块里的代码。

4 QTcpSocket *connect = serve->nextPendingConnection();

  • 功能:调用 QTcpServer 类的 nextPendingConnection() 函数,其作用是从等待处理的连接队列中取出下一个连接,并返回一个指向 QTcpSocket 对象的指针。这个 QTcpSocket 对象代表了与客户端的连接,可用于和客户端进行数据的读写操作。
  • 变量connect 是一个指向 QTcpSocket 对象的指针,借助它就能对与客户端的连接进行操作。
  • 注意事项:需要注意的是,connect 是 C++ 的关键字,使用它作为变量名会引发编译错误,建议使用其他名称,例如 socket

5 QNetworkInterface::allAddresses();

得到主机上的所有地址

6 QTcpSocket *temp=qobject_cast<QTcpSocket*>(sender());

在完成串口的时候也用到了(主要找到信号的发出者)

在代码 QTcpSocket *temp = qobject_cast<QTcpSocket*>(sender()); 中:

  • sender() 会返回发出当前信号的对象的指针。
  • qobject_cast<QTcpSocket*>(sender()) 会尝试把这个指针转换为 QTcpSocket* 类型。如果发出信号的对象确实是 QTcpSocket 类型或者是其子类,就会返回指向该对象的 QTcpSocket* 指针;若不是,就会返回 nullptr
  • 最后把转换后的指针赋值给 temp,这样在后续代码中就可以使用 temp 指针来操作这个 QTcpSocket 对象了,比如读取数据、发送数据等。

二 网络调试助手(服务端)

1 完成界面设计

2 创建服务对象和实现简单通讯

这段代码的主要作用是创建一个 TCP 服务器,监听指定的 IP 地址(192.168.26.5)和端口号(8888),当有新的客户端连接到服务器时,输出客户端的 IP 地址和端口号。它利用了 Qt 的 QTcpServer 类和信号与槽机制,实现了简单的服务器端通信功能。不过需要注意的是,代码中的 QTcpSocket *connect 变量名使用了 C++ 关键字 connect,建议将其改为其他名称,避免编译错误。

#include "widget.h"
#include "ui_widget.h"
#include"QTcpSocket"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //初始化网络服务对象
    serve=new QTcpServer(this);
    //主机的地址
    QHostAddress host("192.168.26.5");
    //检查是否监听成功 同时设置主机的地址和主机的端口号
    if(!serve->listen(host,8888)){
        qDebug()<<"listen Error";
        return;
    }

    //建立连接
    connect(serve,&QTcpServer::newConnection,this,&Widget::on_newClient_connect);
}

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

void Widget::on_newClient_connect()
{
    qDebug()<<"IN NewConnect to Clicent";
    //检查服务器是否有等待处理的客户端连接请求。
   if(serve->hasPendingConnections()){
       //调用 QTcpServer 类的 nextPendingConnection() 函数,其作用是从等待处理的连接队列中取出下一个连接,
       //并返回一个指向 QTcpSocket 对象的指针。这个 QTcpSocket 对象代表了与客户端的连接,可用于和客户端进行数据的读写操作
       QTcpSocket *connect=serve->nextPendingConnection();
       qDebug()<<"Client address"<<connect->peerAddress()<<"Clinet port"<<connect->peerPort();

   }

}

3 结合ui界面上的按钮实现上面功能

#include "widget.h"
#include "ui_widget.h"
#include"QTcpSocket"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //初始化网络服务对象
    serve=new QTcpServer(this);
    //建立连接
    connect(serve,&QTcpServer::newConnection,this,&Widget::on_newClient_connect);
    //监听过过后才可以选择
    ui->btn_stop->setEnabled(false);
    ui->btn_break->setEnabled(false);


}

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

void Widget::on_newClient_connect()
{
    qDebug()<<"IN NewConnect to Clicent";
    //检查服务器是否有等待处理的客户端连接请求。
   if(serve->hasPendingConnections()){
       //调用 QTcpServer 类的 nextPendingConnection() 函数,其作用是从等待处理的连接队列中取出下一个连接,
       //并返回一个指向 QTcpSocket 对象的指针。这个 QTcpSocket 对象代表了与客户端的连接,可用于和客户端进行数据的读写操作
       QTcpSocket *connect=serve->nextPendingConnection();
       //在接收text上显示客户端的信息
       ui->textEdit_rec->setText("客户端的地址:"+connect->peerAddress().toString()+"\n客户端端口号:"+QString::number(connect->peerPort()));



   }

}


void Widget::on_btn_start_clicked()
{

    //serve->listen(QHostAddress::Any,8888); QHostAddress::Any自动获取当前主机地址
    //主机的地址
    QHostAddress host("192.168.26.5");
    //检查是否监听成功 同时设置主机的地址和主机的端口号

    if(!serve->listen(host,ui->lineEdit_port->text().toInt())){
        qDebug()<<"listen Error";
        return;
    }
    //监听按钮不可选其他可选
    ui->btn_start->setEnabled(false);
    ui->btn_stop->setEnabled(true);
    ui->btn_break->setEnabled(true);

}

4 服务端自动刷新IPV4地址

//创建存储能ip的列表
//QNetworkInterface::allAddresses();得到主机上的所有地址
QList <QHostAddress> list_add=QNetworkInterface::allAddresses();
for(QHostAddress add : list_add){
    //是否符合IPV4的格式符合就加入
    if(add.protocol()==QAbstractSocket::IPv4Protocol){
        ui->comboBox_IP->addItem(add.toString());
    }
}

5 服务端接收数据

void Widget::on_receive()
{
    //因为connection是局部变量 所以要得到信号的发出者connection应该这样做
    QTcpSocket *temp=qobject_cast<QTcpSocket*>(sender());
    //接收客户端的数据
    QByteArray arr= temp->readAll();
    //服务端显示数据 并转化为utf-8
    ui->textEdit_rec->append(QString::fromUtf8(arr));


}

6 实现接收数据的时候显示时间

    //设置时间对象调用QDateTime::currentDateTime()获取当前时间
    QDateTime CurrentTime=QDateTime::currentDateTime();
    //在你给出的代码里,toString 是 QDateTime 类的一个成员函数,其作用是把 QDateTime 对象转换为特定格式的字符串。
    QString time_str=CurrentTime.toString("yyyy-MM-dd hh:mm:ss");
    ui->textEdit_rec->append(time_str+"\n"+QString::fromUtf8(arr));

7 服务端发送数据

//发送按钮功能实现
void Widget::on_pushButton_sent_clicked()
{



    //得到输入的文字
//    QString sent_str=ui->textEdit_sent->toPlainText();
//    if(!sent_str.isEmpty()){
//        for(QTcpSocket *tcp:List_Tcp){
//            //已经连接
//            if(tcp->state()==QAbstractSocket::ConnectedState){
//                tcp->write(sent_str.toUtf8());

//                //在 Qt 的网络编程中,socket->flush();
//                //是 QTcpSocket 类对象调用的一个成员函数,其主要作用是强制将输出缓冲区中的数据立即发送到网络中。
//                tcp->flush();
//            }
//        }
//    }
    //还可以通过
    // 这行代码把 serve 对象及其所有子对象中找到的 QTcpSocket 对象的指针存储在 stocket 列表中;
    //stocket存储着多个客户端都可以进行接收服务端放的数据
   QList<QTcpSocket*> stocket= serve->findChildren<QTcpSocket*>();
   for(QTcpSocket *tcp:stocket){
    tcp->write(ui->textEdit_sent->toPlainText().toUtf8());
   }
}

8 服务端选择特点的客户端(自定义控件实现)

将该控件提升为MyComBoBox

断开连接的时候会出现端口号0 利用tcp!=nullptr&&tcp->peerPort()!=0可以解决 (没有根本解决 只是页面上不显示其实还存在在)根本解决在断开的时候删除connection

//刷新连接的端口
void Widget::on_refresh()
{
    //先刷新
    ui->comboBox_choose->clear();

    //  这行代码把 serve 对象及其所有子对象中找到的 QTcpSocket 对象的指针存储在 stocket 列表中;
    QList<QTcpSocket*> sto=serve->findChildren<QTcpSocket*>();
    for(QTcpSocket *tcp:sto){
        //显示端口号
        //断开连接的时候会出现端口号0 利用tcp!=nullptr&&tcp->peerPort()!=0可以解决 (没有根本解决 只是页面上不显示其实还存在在)
        //根本解决在断开的时候删除connection

        if(tcp!=nullptr&&tcp->peerPort()!=0){

            ui->comboBox_choose->addItem(QString::number(tcp->peerPort()));

        }
    }
    ui->comboBox_choose->addItem("ALL");
}

根本解决在断开的时候删除connection

9 中止和监听按钮实现

//中止
void Widget::on_btn_stop_clicked()
{
    //每一个都要停止
    QList<QTcpSocket*> sto=serve->findChildren<QTcpSocket*>();
    for(QTcpSocket *tcp:sto){
        tcp->close();
    }
    //最后服务端也要停止
    serve->close();
    ui->btn_stop->setEnabled(false);
    ui->btn_break->setEnabled(false);
    ui->btn_start->setEnabled(true);
}

//中断
void Widget::on_btn_break_clicked()
{
    //中断先停止
    on_btn_stop_clicked();
    //删除服务端
    serve->deleteLater();
    //关闭窗口
    this->close();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值