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() {
  	//处理断开连接请求
  }
相关推荐
kiiila26 分钟前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
黄金右肾4 小时前
Qt之数据库使用(十四)
sql·qt·sqlite·database
杨德杰5 小时前
QT多媒体开发(一):概述
qt·音视频·多媒体
小王爱吃月亮糖6 小时前
QT开发【常用控件1】-Layouts & Spacers
开发语言·前端·c++·qt·visual studio
864记忆6 小时前
关于opencv、Qt、msvc编译器之间的关系
人工智能·qt·opencv
总是学不会.6 小时前
第五篇:前后端如何“扯皮”——HTTP 在开发中的应用
java·网络·网络协议·http·开发
m0_748238278 小时前
WebClient HTTP 请求问题处理模板(泛型响应、忽略 SSL 证书等)
网络协议·http·ssl
୧⍢⃝୨ LonelyCoder9 小时前
FreePBX修改IP地址和端口以及添加SSL证书开启HTTPS访问
tcp/ip·https·ssl
轩辰~9 小时前
网络协议入门
linux·服务器·开发语言·网络·arm开发·c++·网络协议
Ven%10 小时前
如何在防火墙上指定ip访问服务器上任何端口呢
linux·服务器·网络·深度学习·tcp/ip