简介
- 软件开发中,可能经常会用到TCP调试工具。本人使用QT开发了一款TCP调试工具,方便大家使用。本文章主要介绍下,该工具的功能,以及如何在Qt中实现TCP服务器的并发。
界面展示
- 安装界面
- 桌面图标。安装后会生成桌面图标,双击图标可以打开程序。
- 界面展示
功能说明
- 本程序使用Qt实现了TCP客户端和服务端,服务端并发数默认为100,可配置。客户端连接后,可以在服务端看到连接的客户端信息,服务端可以指定给某一个客户端发送消息。
- 服务端不支持广播,后续版本会完善。
软件下载
- 本程序已经制作成安装包形式,下载安装后可直接使用。
- gitee下载
- CSDN资源下载
Qt实现服务端并发
- Qt实现服务端多并发时,可以实现一个类 TcpServerTools,该类需要继承于 QTcpServer,然后重写以下两个函数
- void setMaxPendingConnections(int numConnections);
- 该函数设置服务端最大连接数
- void incomingConnection(qintptr socketDescriptor);
- 当有新连接时,会触发该函数,我们需要在该函数中,将套接字保存起来。可以将套接字保存到一个Hash中 QHash<int, TcpSocketTools*>
核心源代码
-
这里只提供了服务端实现并发的核心源代码,主要有三个文件networkdebugtools.cpp为主界面文件,实现UI交互。tcpservertools.cpp主要实现接受客户端连接请求,保存套接字到hash容器中。tcpsockettools.cpp中主要实现处理客户端数据和断开请求。
-
三者之间可以自己定义信号槽实现通信,整体源代码不提供,请谅解。
-
networkdebugtools.h
-
#ifndef NETWORKDEBUGTOOLS_H #define NETWORKDEBUGTOOLS_H #include <QWidget> #include <QEvent> #include <QMouseEvent> #include <QMenu> #include "tcpservertools.h" #include <map> QT_BEGIN_NAMESPACE namespace Ui { class NetworkDebugTools; } QT_END_NAMESPACE class NetworkDebugTools : public QWidget { Q_OBJECT public: NetworkDebugTools(QWidget *parent = nullptr); ~NetworkDebugTools(); private slots: void on_pushButton_send_clicked(); void on_pushButton_listen_clicked(); private: Ui::NetworkDebugTools *ui; TcpServerTools *mTcpServerTools; }; #endif // NETWORKDEBUGTOOLS_H
-
networkdebugtools.cpp
-
#include "networkdebugtools.h" #include "ui_networkdebugtools.h" #include <QMessageBox> #include <QHostInfo> #include <QTableWidgetItem> #include "comm.h" NetworkDebugTools::NetworkDebugTools(QWidget *parent) : QWidget(parent) , ui(new Ui::NetworkDebugTools) { ui->setupUi(this); mTcpServerTools = new TcpServerTools(); } void NetworkDebugTools::on_pushButton_send_clicked() { //获取当前选中的客户端信息 QString curAddr = ui->tableWidget_clientInfo->item(curRow, 0)->text(); QHash<int, TcpSocketTools*>::iterator iter = mTcpServerTools->tcpClient->begin(); for (; iter != mTcpServerTools->tcpClient->end(); iter++) { QString iterAddr = iter.value()->peerAddress().toString() + ":" + QString::number(iter.value()->peerPort()); if (iterAddr.compare(curAddr) == 0) { //这里hash容器tcpClient中保存的value就是socket,可以直接通过socket给客户端发送数据 //同样可以通过该socket获取客户端的ip和端口,然后与我们点击的客户端信息比对,就可以实现对指定客户端发送消息 iter.value()->write(ui->plainTextEdit_send->toPlainText().toLocal8Bit()); break; } } } void NetworkDebugTools::on_pushButton_listen_clicked() { if (ui->pushButton_listen->text().compare("监听") == 0) { ui->pushButton_listen->setText("关闭"); mTcpServerTools->setMaxPendingConnections(mConfigTools->getConnCount()); mTcpServerTools->startListen(); } else { ui->pushButton_listen->setText("监听"); mTcpServerTools->closeConnect(); } }
-
tcpservertools.h
-
#ifndef TCPSERVERTOOLS_H #define TCPSERVERTOOLS_H #include <QWidget> #include <QTcpServer> #include <QHostInfo> #include <QAbstractSocket> #include <QTcpSocket> #include "tcpsockettools.h" #define THREAD_MAX 20 class TcpServerTools : public QTcpServer { Q_OBJECT public: explicit TcpServerTools(QTcpServer *parent = 0); ~TcpServerTools(); //开始监听 bool startListen(); //关闭连接 void closeConnect(); //设置最大连接数 void setMaxPendingConnections(int numConnections); protected: // 有新连接到来时,该函数会被触发 void incomingConnection(qintptr socketDescriptor); private: QTcpServer *mTcpServer; //tcp服务对象 public: QHash<int, TcpSocketTools*> *tcpClient;// 该对象中保存套接字 }; #endif // TCPSERVERTOOLS_H
-
tcpservertools.cpp
-
#include "tcpservertools.h" TcpServerTools::TcpServerTools(QTcpServer *parent) : QTcpServer(parent) { tcpClient = new QHash<int, TcpSocketTools*>; } TcpServerTools::~TcpServerTools() { } bool TcpServerTools::startListen() { //监听连接 this->listen(QHostAddress(mIp), mPort.toInt()); return true; } void TcpServerTools::closeConnect(){ // 断开连接时,删除tcpClient中保存的套接字,并清除 tcpClient QHash<int, TcpSocketTools*>::const_iterator iterC = tcpClient->constBegin(); for (; iterC != tcpClient->constEnd(); iterC++){ iterC.value()->deleteLater(); } tcpClient->clear(); this->close(); } void TcpServerTools::incomingConnection(qintptr socketDescriptor) { //创建 TcpSocketTools 对象 TcpSocketTools *socketTools = new TcpSocketTools(socketDescriptor); QString connAddr = socketTools->peerAddress().toString() + ":" + QString::number(socketTools->peerPort()); // 有新连接时,保存socket到 QHash<int, TcpSocketTools*> 类型的tcpClient指针对象中 tcpClient->insert(socketDescriptor, socketTools); } // 设置最大连接数 void TcpServerTools::setMaxPendingConnections(int numConnections) { QTcpServer::setMaxPendingConnections(numConnections); }
-
tcpsockettools.h
-
#ifndef TCPSOCKETTOOLS_H #define TCPSOCKETTOOLS_H #include <QTcpSocket> class TcpSocketTools : public QTcpSocket { Q_OBJECT public: explicit TcpSocketTools(qintptr socketDescriptor, QTcpSocket *parent = 0); ~TcpSocketTools(); public slots : void onReadyRead(); void onDisconnected(); private: qintptr socketID; }; #endif // TCPSOCKETTOOLS_H
-
tcpsockettools.cpp
-
#include "tcpsockettools.h" #include <QHostAddress> TcpSocketTools::TcpSocketTools(qintptr socketDescriptor, QTcpSocket *parent) : QTcpSocket(parent),socketID(socketDescriptor) { this->setSocketDescriptor(socketDescriptor); connect(this, &TcpSocketTools::readyRead, this, &TcpSocketTools::onReadyRead); connect(this, &TcpSocketTools::disconnected, this, &TcpSocketTools::onDisconnected); } TcpSocketTools::~TcpSocketTools() { } void TcpSocketTools::onReadyRead() { //处理接受到的数据 } void TcpSocketTools::onDisconnected() { //处理断开连接请求 }