• QT开发之旅二TCP调试工具


    TCP调试工具顾名思义用来调试TCP通信的,网上这样的工具N多,之前用.NET写过一个,无奈在XP下还要安装个.NET框架才能运行,索性这次用QT重写,发现QTTCP通信比.NET还要便捷一些,运行效率貌似要高,还能识别客户端断开,这个真神奇,除了断电之外。

    项目名称:TCP调试工具

    开发环境:WIN7+QT4.7+QT CREATOR2.8+MINGW

    技术实现:通过QTcpServerQTcpSocket类,解析协议并作出处理

    实现功能:ASCII格式和16进制数据收发,支持多个客户端收发消息,可以指定客户端发送消息,动态增加和移除已连接客户端。

    运行截图:

     

    粗略步骤:

    第一步:添加主界面,布局好主界面,并命名好控件,例如服务端的清空按钮命名为btnClearServer,客户端的清空按钮命名为btnClearClient

    第二步:编写服务端中客户端通信类,服务端可以接受多个客户端的连接,这里采用了同步通信机制,先编写myTcpClient类,封装了客户端连接断开接收数据的操作。具体代码如下:

     

    myTcpClient.h
    
    #ifndef MYTCPCLIENT_H
    
    #define MYTCPCLIENT_H
    
     
    
    #include <QTcpSocket>
    
     
    
    class myTcpClient : public QTcpSocket
    
    {
    
        Q_OBJECT
    
    public:
    
        explicit myTcpClient(QObject *parent = 0,int clientID=0);
    
     
    
    private:
    
        int clientID;
    
        
    
    signals:
    
        void ClientReadData(int clientID,QString IP,int Port,QByteArray data);
    
        void ClientDisConnect(int clientID,QString IP,int Port);
    
        
    
    private slots:
    
        void ReadData();
    
        void DisConnect();
    
     
    
    public slots:
    
     
    
    };
    
     
    
    #endif // MYTCPCLIENT_H
    
     
    
    myTcpClient.cpp
    
    #include "mytcpclient.h"
    
    #include <QHostAddress>
    
    #include "myhelper.h"
    
     
    
    myTcpClient::myTcpClient(QObject *parent,int clientID) :
    
        QTcpSocket(parent)
    
    {    
    
        this->clientID=clientID;
    
        connect(this,SIGNAL(readyRead()),this,SLOT(ReadData()));//挂接读取数据信号
    
        connect(this,SIGNAL(disconnected()),this,SLOT(DisConnect()));//关闭连接时,发送断开连接信号
    
        //如果关闭连接自动删除,则下次不能再次监听,奇怪的问题
    
        //connect(this,SIGNAL(disconnected()),this,SLOT(deleteLater()));//关闭连接时,对象自动删除
    
    }
    
     
    
    void myTcpClient::ReadData()
    
    {
    
        myHelper::Sleep(100);
    
        //读取完整一条数据并发送信号
    
        QByteArray data=this->readAll();
    
        emit ClientReadData(this->clientID,this->peerAddress().toString(),this->peerPort(),data);
    
    }
    
     
    
    void myTcpClient::DisConnect()
    
    {
    
        //断开连接时,发送断开信号
    
        emit ClientDisConnect(this->clientID,this->peerAddress().toString(),this->peerPort());
    
    }
    

     

     

    一旦客户端断开则发送ClientDisConnect信号,参数包含IP地址和端口。

     

    第三步:编写服务端通信类。

    myTcpServer.h
    
    #ifndef MYTCPSERVER_H
    
    #define MYTCPSERVER_H
    
     
    
    #include <QTcpServer>
    
    #include "mytcpclient.h"
    
     
    
    class myTcpServer : public QTcpServer
    
    {
    
        Q_OBJECT
    
    public:
    
        explicit myTcpServer(QObject *parent = 0);
    
        void SendData(int clientID, QByteArray data);
    
        void SendDataCurrent(QByteArray data);
    
        void SendDataAll(QByteArray data);
    
     
    
        int ClientCount()const{return clientCount;}
    
        void CloseAllClient();
    
     
    
    private:
    
        QList<myTcpClient *> ClientList;
    
        QList<int> ClientID;
    
        myTcpClient *CurrentClient;
    
     
    
        int clientCount;
    
     
    
    protected:
    
        void incomingConnection(int handle);
    
        
    
    signals:
    
        void ClientReadData(int clientID,QString IP,int Port,QByteArray data);
    
        void ClientConnect(int clientID,QString IP,int Port);
    
        void ClientDisConnect(int clientID,QString IP,int Port);
    
        
    
    private slots:    
    
        void DisConnect(int clientID,QString IP,int Port);
    
     
    
    public slots:
    
        
    
    };
    
     
    
    #endif // MYTCPSERVER_H
    
     
    
    myTcpServer.cpp
    
    #include "mytcpserver.h"
    
    #include <QHostAddress>
    
     
    
    myTcpServer::myTcpServer(QObject *parent) :
    
        QTcpServer(parent)
    
    {
    
        this->clientCount=0;
    
    }
    
     
    
    void myTcpServer::incomingConnection(int handle)
    
    {
    
        myTcpClient *client=new myTcpClient(this,handle);
    
        client->setSocketDescriptor(handle);
    
     
    
        connect(client,SIGNAL(ClientReadData(int,QString,int,QByteArray)),this,SIGNAL(ClientReadData(int,QString,int,QByteArray)));
    
        connect(client,SIGNAL(ClientDisConnect(int,QString,int)),this,SLOT(DisConnect(int,QString,int)));
    
     
    
        emit ClientConnect(handle, client->peerAddress().toString(),client->peerPort());
    
     
    
        ClientList.append(client);//将新的连接添加到客户端列表
    
        ClientID.append(handle);//将新的连接的ID添加到客户端ID列表
    
        clientCount++;
    
     
    
        //存储当前连接
    
        CurrentClient=client;
    
    }
    
     
    
    void myTcpServer::DisConnect(int clientID,QString IP,int Port)
    
    {
    
        for (int i=0;i<clientCount;i++)
    
        {
    
            if (ClientID[i]==clientID)
    
            {
    
                ClientList.removeAt(i);//从列表中移除该连接
    
                ClientID.removeAt(i);
    
                clientCount--;
    
                i--;//不然的话,永远只会移除第一个连接
    
                emit ClientDisConnect(clientID,IP,Port);
    
                break;
    
            }
    
        }
    
    }
    
     
    
    //指定客户端连接发消息
    
    void myTcpServer::SendData(int clientID, QByteArray data)
    
    {
    
        for (int i=0;i<clientCount;i++)
    
        {
    
            if (ClientID[i]==clientID)
    
            {
    
                ClientList[i]->write(data);
    
                break;
    
            }
    
        }
    
    }
    
     
    
    //对当前连接发送数据
    
    void myTcpServer::SendDataCurrent(QByteArray data)
    
    {
    
        //如果没有一个存在的连接,则不处理
    
        if (clientCount<1){return;}
    
        CurrentClient->write(data);
    
    }
    
     
    
    //对所有连接发送数据
    
    void myTcpServer::SendDataAll(QByteArray data)
    
    {
    
        for (int i=0;i<clientCount;i++)
    
        {
    
            ClientList[i]->write(data);
    
        }
    
    }
    
     
    
    void myTcpServer::CloseAllClient()
    
    {
    
        for (int i=0;i<clientCount;i++)
    
        {
    
            ClientList[i]->close();
    
            i--;//不然的话,永远只会断开第一个连接
    
        }
    
    }
    
    

      

    这里封装了指定客户端发消息,对当前连接发消息,对所有客户端发消息三种发送消息方法。

    最开始的时候发现直接close停止监听,发现依然可以接收客户端的消息,原因是还没有关闭客户端连接,所以增加了CloseAllClient()方法,用来关闭所有客户端连接,这样的话才是彻底的停止监听。

    可执行文件下载地址:http://download.csdn.net/detail/feiyangqingyun/6717009

    源码猛点这里:http://download.csdn.net/detail/feiyangqingyun/6717017

  • 相关阅读:
    MySQL讲义
    python使用matplotlib在一个图形中绘制多个子图以及一个子图中绘制多条动态折线问题
    python爬虫登陆网页版腾讯课堂
    父子组件之间相互传值
    echarts图中使用到的属性及对应的作用,饼图实例、折线图实例
    vue get类型接口调用方式
    javaScript前进后退点击事件
    vue页面跳转
    如何修改vant组件中原有样式?
    Module not found: Error: Can't resolve 'less-loader' in '文件位置'报错解决
  • 原文地址:https://www.cnblogs.com/feiyangqingyun/p/3475228.html
Copyright © 2020-2023  润新知