• Qt5 编写网络调试助手


    QT中可以通过TCP协议让服务器和客户端之间行通信。所以下面我就围绕服务器和客户端来写。

    这是我们写服务器和客户端的具体流程:

    A、服务器:      

             1.创建QTcpServer对象
             2.启动服务器(监听)调用成员方法listen(QHostAddress::Any,端口号)
             3.当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)
             4.QTcpsocket发送数据用成员方法write,
             5.读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

    B、客户端  :  

            1.创建QTcpSocket对象
            2.链接服务器connectToHost(QHostAddress("ip"),端口号)
            3.QTcpsocket发送数据用成员方法write,
            4.读数据当对方有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

    我们需要调用到的头文件有两个:

    #include <QTcpServer>  
    #include <QTcpSocket>

    我们先要在工程文件中加入network

    QT       += core gui network

    下面我们来看看服务器程序步骤:

    1、初始化服务器server对象

    mServer = new QTcpServer();

    2、启动监听服务器

      mServer->listen(QHostAddress::Any,9988);//9988为端口号

    3、当有客户端链接时候会发送newConnection信号,触发槽函数接受链接(得到一个与客户端通信的套接字QTcpSocket)

     connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client()));
     mSocket = mServer->nextPendingConnection();//与客户端通信的套接字

    4、发送数据

     mSocket->write(msg.toUtf8());

    5、读数据当客户端有数据来,QTcpSocket对象就会发送readyRead信号,关联槽函数读取数据

     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_client_data()));

    6、连接多个客户端

     //可以实现同时读取多个客户端发送过来的消息
     QTcpSocket *obj = (QTcpSocket*)sender();

    7、检测掉线

     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis())); //检测掉线信号

    下面是服务器的实现的具体代码:

    复制代码
     1 #include "tcpserver.h"
     2 #include "ui_tcpserver.h"
     3 #include <QDebug>
     4 TcpServer::TcpServer(QWidget *parent) :
     5     QMainWindow(parent),
     6     ui(new Ui::TcpServer)
     7 {
     8     ui->setupUi(this);
     9     //初始化服务器server对象
    10     mServer = new QTcpServer();
    11     //关联客户端连接信号newConnection
    12     connect(mServer,SIGNAL(newConnection()),this,SLOT(new_client())); //连接客户端
    13     //启动服务器监听
    14     mServer->listen(QHostAddress::Any,9988);
    15 
    16 }
    17 
    18 TcpServer::~TcpServer()
    19 {
    20     delete ui;
    21 }
    22 
    23 void TcpServer::new_client()
    24 {
    25     qDebug()<<"新客户段连接";
    26     mSocket = mServer->nextPendingConnection();//与客户端通信的套接字
    27     //关联接收客户端数据信号readyRead信号(客户端有数据就会发readyRead信号)
    28     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_client_data()));
    29     //检测掉线信号
    30     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
    31 
    32 }
    33 
    34 void TcpServer::read_client_data()
    35 {
    36     //可以实现同时读取多个客户端发送过来的消息
    37     QTcpSocket *obj = (QTcpSocket*)sender();
    38     QString msg = obj->readAll();
    39     qDebug()<<msg;
    40 }
    41 
    42 void TcpServer::client_dis()
    43 {
    44      QTcpSocket *obj = (QTcpSocket*)sender();//掉线对象
    45      qDebug()<<obj->peerAddress().toString();//打印出掉线对象的ip
    46 }
    复制代码

    说完服务器那我们继续来看看客户端是怎么实现的:

    1、创建QTcpSocket对象

     mSocket = new QTcpSocket();

    2、链接服务器connectToHost(QHostAddress("ip"),端口号),连接服务器ip和端口号

     mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt()); //ui->ipEdit->text():ip,ui->portEdit->text().toInt():端口号

    3、发送数据

    //取发送信息编辑框内容
    QString msg = ui->sendEdit->toPlainText();
    mSocket->write(msg.toUtf8());//转编码

    4、检测链接成功信号关联槽函数

     connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));

    5、检测掉线信号

     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));

    6、服务器和客户端关闭都可以使用close

     mSocket->close();

    这是客户端实现的具体代码

    复制代码
     1 #include "tcpclient.h"
     2 #include "ui_tcpclient.h"
     3 #include <QDebug>
     4 TcpClient::TcpClient(QWidget *parent) :
     5     QMainWindow(parent),
     6     ui(new Ui::TcpClient)
     7 {
     8     ui->setupUi(this);
     9     //初始化套接字对象
    10     mSocket = new QTcpSocket();
    11     //关联数据信号
    12     connect(mSocket,SIGNAL(readyRead()),this,SLOT(read_data()));
    13 
    14 }
    15 
    16 TcpClient::~TcpClient()
    17 {
    18     delete ui;
    19 }
    20 
    21 void TcpClient::read_data()
    22 {
    23     QString msg = mSocket->readAll();
    24     qDebug()<<msg;
    25 }
    26 
    27 void TcpClient::on_btn_connectServer_clicked()
    28 {
    29     //检测链接成功信号关联槽函数
    30     connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
    31     //检测掉线信号
    32     connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_dis()));
    33     //连接服务器,设置ip和端口号
    34     mSocket->connectToHost(ui->ipEdit->text(),ui->portEdit->text().toInt());
    35 
    36 }
    37 
    38 void TcpClient::on_btn_send_clicked()
    39 {
    40     //取发送信息编辑框内容
    41     QString msg = ui->sendEdit->toPlainText();
    42     mSocket->write(msg.toUtf8());//转编码
    43 }
    44 
    45 void TcpClient::connect_suc()
    46 {
    47     ui->btn_connectServer->setEnabled(false);//如果连接成功则连接按钮不能按下
    48 }
    49 void TcpClient::client_dis()
    50 {
    51     ui->btn_connectServer->setEnabled(true);//如果连接没有成功则连接按钮还可以按下
    52 }
    复制代码

    这是服务器和客户端分开两个文件夹写的程序,在这里我也实现了服务器和客户端写在同一个文件中

    具体代码如下:

    头文件:tcpapp.h

    #ifndef TCPAPP_H
    #define TCPAPP_H
    
    #include <QMainWindow>
    #include <QTcpServer>
    #include <QTcpSocket>
    #include <QHostAddress>
    #include <QFile>
    #include <QTimer>
    #include <QMessageBox>
    namespace Ui {
    class TcpApp;
    }
    
    class TcpApp : public QMainWindow
    {
        Q_OBJECT
    
    public:
        explicit TcpApp(QWidget *parent = 0);
        ~TcpApp();
    
    private slots:
        void on_severRB_clicked();//选择作为服务器
    
        void on_clientRB_clicked();//选择作为客户端
    
        void on_StartBt_clicked();//启动服务器或链接客户端
    
        void on_closeBt_clicked();//关闭服务器或断开客户端
    
        void on_onlineUserList_doubleClicked(const QModelIndex &index);//选择给哪个客户端发送数据
    
        void on_autoCB_clicked(bool checked);//选择自动发送还是手动发送
    
        void on_sendMsgBt_clicked();//发送信息
    
        //服务器
        void accept_connect();//与newconnection信号关联
        void recv_data(); //接收数据
    
         void auto_time_send();//定时器定时发送数据
    
         void client_disconnect();//关联掉线信号
         void connect_suc();//检测客户端连接成功信号
    
         void on_clearRcvBt_clicked();
    
         void on_clearSendBt_clicked();
    
    private:
        Ui::TcpApp *ui;
        QTimer *mTimer;//定时发送数据
        QTcpServer *mServer;
        QTcpSocket *mSocket;
        QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
    
        bool isServer;//标志位,true为服务器,false为客户端
    
        //保存接收和发送数据的字节数
        quint64 recvSize;
        quint64 sendSize;
    
        qint16 onNum;
        bool isCheckServer;//判断是否选择了服务器
        bool isCheckClient;//判断是否选择了客户端
    
    
    };
    
    #endif // TCPAPP_H

    源文件:tcpapp.cpp

    #include "tcpapp.h"
    #include "ui_tcpapp.h"
    
    TcpApp::TcpApp(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::TcpApp),
        onNum(0)
    {
        ui->setupUi(this);
        recvSize = 0;
        sendSize = 0;
        //初始化定时器
        mTimer = new QTimer();
        connect(mTimer,SIGNAL(timeout()),this,SLOT(auto_time_send()));
    }
    
    TcpApp::~TcpApp()
    {
        delete ui;
    }
    
    //与newconnection信号关联
    void TcpApp::accept_connect()
    {
        mSocket = mServer->nextPendingConnection(); //返回与客户端连接通信的套接字
    
        //关联接收数据信号
        connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
        //关联掉线信号
        connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
    
        //上线用户添加到客户列表容器
        clients.append(mSocket);
        //把用户添加到界面列表中
        QString ip = mSocket->peerAddress().toString().remove("::ffff:");//去除客户端中多余的字符
        ui->onlineUserList->addItem(ip);
    
        //在线数量添加
        onNum++;
        ui->onlineUserCount->setText(QString::number(onNum));//显示在线数
    
    }
    
    //接收数据
    void  TcpApp::recv_data()
    {
          QTcpSocket *obj = (QTcpSocket*)sender();
          //获取发送数据端的IP
          QString ip = obj->peerAddress().toString();
          ip.remove("::ffff:");
          QString msg = obj->readAll();
          ui->receiveList->addItem(ip+":"+msg);//显示接收到的数据
          recvSize += msg.size();//统计接收到的数据的字节数
          ui->receiveNumLabel->setText(QString::number(recvSize));
    }
    
    void TcpApp::client_disconnect()
    {
        QTcpSocket *obj = (QTcpSocket*)sender();//获取掉线对象
        if(isServer)
        {
            int row = clients.indexOf(obj);//找到掉线对象的内容所在的行
            QListWidgetItem *item = ui->onlineUserList->takeItem(row);//从界面列表中去除找到的一行内容
            delete item;
            clients.remove(row);//从容器中删除对象
    
            //掉线时删除在线数量
            onNum--;
            ui->onlineUserCount->setText(QString::number(onNum));
        }
        else
        {
            ui->StartBt->setEnabled(true);//断开连接的时候重新启用开始按钮
        }
    }
    
    
    //客户端连接成功
    void TcpApp::connect_suc()
    {
        ui->StartBt->setEnabled(false);//连接成功则禁用开始按钮
    }
    //定时器定时发送数据
    void TcpApp::auto_time_send()
    {
        quint64 len = mSocket->write(ui->sendMsgEdit->toPlainText().toUtf8());
        if(len > 0)
        {
            sendSize += len;//统计发送的字节数
            ui->sendNumLabel->setText(QString::number(sendSize));//把发送的字节数显示到sendNumLabel上
    
        }
    }
    
    //选择作为服务器
    void TcpApp::on_severRB_clicked()
    {
        this->isCheckServer = true;
        this->isServer = true;
        //获取本地ip显示在IpEdit中
       ui->IpEdit->setText(QHostAddress(QHostAddress::LocalHost).toString());
       ui->IpEdit->setEnabled(false);//关闭ip输入编辑器
       this->isCheckClient = false;
    
    }
    
    //选择作为客户端
    void TcpApp::on_clientRB_clicked()
    {
        this->isCheckClient = true;
        this->isServer = false;
        ui->IpEdit->setEnabled(true);//打开ip输入编辑器
        this->isCheckServer = false;
    
    }
    
    //启动服务器或者链接服务器
    void TcpApp::on_StartBt_clicked()
    {
        if(isServer) //服务器
        {
            mServer = new QTcpServer();
            //关联新客户端链接信号
            connect(mServer,SIGNAL(newConnection()),this,SLOT(accept_connect()));
            mServer->listen(QHostAddress::Any,ui->PortEdit->text().toInt());//启动服务器监听
            ui->StartBt->setEnabled(false);//开始按钮禁用
        }
        if(isServer == false) //客户端
        {
            mSocket = new QTcpSocket();
            //检测链接成功信号
            connect(mSocket,SIGNAL(connected()),this,SLOT(connect_suc()));
            //设置服务器的 ip和端口号
            mSocket->connectToHost(ui->IpEdit->text(),ui->PortEdit->text().toInt());
    
    
            //关联接收数据信号
            connect(mSocket,SIGNAL(readyRead()),this,SLOT(recv_data()));
            //关联掉线信号
            connect(mSocket,SIGNAL(disconnected()),this,SLOT(client_disconnect()));
        }
    
        if(isCheckServer == false && isCheckClient == false)//如果两个都没选择
        {
            QMessageBox::warning(this,"提示","请选择服务器或者客户端");
            ui->StartBt->setEnabled(true);
            return;
        }
    
        if(isCheckServer)//选择了服务器
        {
           if(ui->PortEdit->text().isEmpty() || ui->PortEdit->text() == "请输入端口号")
           {
               QMessageBox::warning(this,"提示","请输入端口号");
               ui->StartBt->setEnabled(true);
               return;
           }
        }
    
        if(isCheckClient)//选择了客户端
        {
            if(ui->IpEdit->text().isEmpty() || ui->IpEdit->text() == "请输入ip" || ui->IpEdit->text() == "请输入端口号")
            {
                QMessageBox::warning(this,"提示","请输入ip和端口号");
                ui->StartBt->setEnabled(true);
                return;
            }
        }
    
    }
    
    //关闭服务器或者断开
    void TcpApp::on_closeBt_clicked()
    {
        if(isServer)//服务器
        {
            for(int i=0;i<clients.count();i++)
            {
                 clients.at(i)->close();//关闭所有客户端
            }
    
            //关闭所有服务器之后开始按钮才能启用
            mServer->close();
            ui->StartBt->setEnabled(true);
        }
        else //客户端
        {
            mSocket->close();//关闭客户端
            ui->StartBt->setEnabled(true);//启用开始按钮
        }
    
    }
    
    //双击选择要发送的客户端
    void TcpApp::on_onlineUserList_doubleClicked(const QModelIndex &index)
    {
        mSocket = clients.at(index.row());
    
    }
    
    //自动发送数据
    void TcpApp::on_autoCB_clicked(bool checked)
    {
        if(checked)
    
        {
            if(ui->autoTimeEdit->text().toInt() <= 0)
            {
                QMessageBox::warning(this,"提示","请输入时间值ms");
                ui->autoCB->setChecked(false);//把按钮重新置于没选中的状态
                return;
            }
            mTimer->start(ui->autoTimeEdit->text().toInt());//启动定时器
        }
        else
        {
            mTimer->stop();//停止定时器
        }
    
    }
    
    //手动发送数据
    void TcpApp::on_sendMsgBt_clicked()
    {
        auto_time_send();
    
    }
    
    //清空接收区
    void TcpApp::on_clearRcvBt_clicked()
    {
        ui->receiveNumLabel->clear();
        this->recvSize = 0;
        ui->receiveNumLabel->setText(QString::number(recvSize));
    }
    
    //清空发送区
    void TcpApp::on_clearSendBt_clicked()
    {
        ui->sendNumLabel->clear();
        this->sendSize = 0;
        ui->sendNumLabel->setText(QString::number(sendSize));
    }

    界面文件tcpapp.ui如下图

     

    此外这里还使用到了容器,在这里讲讲容器的使用

    1、定义容器对象

    QVector<QTcpSocket*> clients; //存储所有在线客户端(容器)
      解释:QTcpSocke*  容器的类型
           clients  容器名

    2、往容器中添加成员

    //上线用户添加到客户列表容器
     clients.append(mSocket); 

    3、寻找某个成员在容器中位置

     int row = clients.indexOf(obj);//找到掉线对象的内容所在的行

    4、从容器中删除成员

      clients.remove(row);//从容器中删除成员
  • 相关阅读:
    mysql 数据操作 单表查询 group by 注意
    mysql 数据操作 单表查询 group by 聚合函数
    mysql 数据操作 单表查询 group by 聚合函数 没有group by情况下
    mysql 数据操作 单表查询 group by 介绍
    【洛谷P3586】LOG
    【YbtOJ#20078】路径之和
    【ABC181】F
    【洛谷P7045】金牌
    【AT2165】Median Pyramid Hard
    【洛谷P3708】koishi的数学题
  • 原文地址:https://www.cnblogs.com/wt88/p/14657183.html
Copyright © 2020-2023  润新知