Qt实现TCP调试助手 - 简述如何在Qt中实现TCP多并发

简介

  • 软件开发中,可能经常会用到TCP调试工具。本人使用QT开发了一款TCP调试工具,方便大家使用。本文章主要介绍下,该工具的功能,以及如何在Qt中实现TCP服务器的并发。

界面展示

  • 安装界面
  • 桌面图标。安装后会生成桌面图标,双击图标可以打开程序。
  • 界面展示

功能说明

  • 本程序使用Qt实现了TCP客户端和服务端,服务端并发数默认为100,可配置。客户端连接后,可以在服务端看到连接的客户端信息,服务端可以指定给某一个客户端发送消息。
  • 服务端不支持广播,后续版本会完善。

软件下载

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

c 复制代码
  #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

c 复制代码
  #include "networkdebugtools.h"
  #include "ui_networkdebugtools.h"
  #include <QMessageBox>
  #include <QHostInfo>
  #include <QTableWidgetItem>
  
  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

c 复制代码
  #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

c 复制代码
  #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

c 复制代码
  #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

c 复制代码
  #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() {
  	//处理断开连接请求
  }
相关推荐
CHENKONG_CK16 分钟前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
Quz1 小时前
QML SwipeDelegate 滑动委托
qt
z落落1 小时前
C#UDP+串口服务端+UDP 客户端(含 CRC16 校验)
网络·网络协议·udp
Quz2 小时前
QML 列表中的四种委托:ItemDelegate、CheckDelegate、RadioDelegate、SwitchDelegate
qt
实心儿儿2 小时前
Qt — 显示类控件
qt
曼巴UE53 小时前
UE5 客户端 需要的网络同步概念总结(3 )-事件同步 RPC 以及三种调用方式
网络·c++·网络协议·学习·rpc·ue5
开开心心就好3 小时前
安卓手写文字生成工具,多种纸张一直免费
网络·网络协议·tcp/ip·leetcode·智能手机·电脑·模拟退火算法
渡我白衣4 小时前
HttpRequest与HttpResponse的实现
服务器·数据结构·c++·人工智能·tcp/ip·机器学习·caffe
江湖人称菠萝包19 小时前
【Qt】《Qt 5.9 C++开发指南》笔记-Chapter9-Qt Charts
笔记·qt·qt5
扶尔魔ocy19 小时前
【QT android】环境安装及第一个QT项目
qt·andriod开发