当前位置:网站首页>Qtcpserver multithreading implementation
Qtcpserver multithreading implementation
2022-07-18 13:38:00 【Progress every day 2015】
Purpose : Each client is connected tcpSocket Assign a special thread to handle .
Inherit respectively when implementing QTcpServer and QTcpScoket Implement the classes you need .
Inherit QTcpServer Allocate threads for each client connection , And receive treatment tcpScoket Signals and slots 、、 And send messages , Store connection information, etc .
Inherit QTcpScoket For processing communication data and adding signal parameters , For harmony tcpServer Better cooperation .
The first is to inherit and rewrite QTcpServer Of incomingConnection Function to implement itself tcpsocket Establishment and distribution of connections .
The default description of the document is :
This virtual function is called by QTcpServer when a new connection is available. The socketDescriptor argument is the native socket descriptor for the accepted connection.
The base implementation creates a QTcpSocket, sets the socket descriptor and then stores the QTcpSocket in an internal list of pending connections. Finally newConnection() is emitted.
Reimplement this function to alter the server’s behavior when a connection is available.
If this server is using QNetworkProxy then the socketDescriptor may not be usable with native socket functions, and should only be used with QTcpSocket::setSocketDescriptor().
Note: If you want to handle an incoming connection as a new QTcpSocket object in another thread you have to pass the socketDescriptor to the other thread and create the QTcpSocket object there and use its setSocketDescriptor() method.
translation ( Google translate and its own simple correction ):
When QTcpServer This virtual function is called when there is a new connection . The socketDescriptor The parameter is the local socket descriptor used to accept the connection .
This function creates a QTcpSocket, And set the socket descriptor to socketDescriptor, Then store QTcpSocket In the internal list of pending connections . Last newConnection() Launched .
Re implement this function to change the behavior of the server , When a connection is available .
If the server uses QNetworkProxy that socketDescriptor May not be compatible with native socket Function USES , And only use QTcpSocket:: setSocketDescriptor() Use in .
Be careful : If you want to handle a new one in another thread QTcpSocket Object incoming connection , You must put the socketDescriptor Pass to other threads , And created QTcpSocket Object exists and uses it setSocketDescriptor() Method .
So we have to rewrite this function first :
The following is attached first QTcpServer Your own class declaration , Personally, I think the code comments are quite detailed :
// Inherit QTCPSERVER To achieve multithreading TCPscoket Server for .
class MyTcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit MyTcpServer(QObject *parent = 0);
~MyTcpServer();
signals:
void connectClient(const int , const QString & ,const quint16 );// Send new user connection information
void readData(const int,const QString &, quint16, const QByteArray &);// Send and get the data sent by the user
void sockDisConnect(const int ,const QString &,const quint16 );// Disconnected user information
void sentData(const QByteArray &,const int);// towards scoket Send a message
public slots:
void setData(const QByteArray & data, const int handle);// Send messages to users
void readDataSlot(const int, const QString &, const quint16,const QByteArray &);// Send and get the data sent by the user
void sockDisConnectSlot(int handle, QString ip, quint16 prot);// Disconnected user information
protected:
void incomingConnection(qintptr socketDescriptor);// Override got multithreaded
private:
QMap<int,myTcpSocket *> * tcpClient;
};Then we rewrite void QTcpServer::incomingConnection(qintptr socketDescriptor) The implementation of the :
void MyTcpServer::incomingConnection(qintptr socketDescriptor)
{
myTcpSocket * tcpTemp = new myTcpSocket(socketDescriptor);
QThread * thread = new QThread(tcpTemp);// Set the parent class of the thread as connected , Prevent memory leaks
// It can connect signals , I want to capture threads ID The function is independent , In use or direct connection, signal efficiency should have advantages
connect(tcpTemp,&myTcpSocket::readData,this,&MyTcpServer::readDataSlot);// Data received
connect(tcpTemp,&myTcpSocket::sockDisConnect,this,&MyTcpServer::sockDisConnectSlot);// Processing of disconnection , Remove from list , And release the disconnected Tcpsocket
connect(this,&MyTcpServer::sentData,tcpTemp,&myTcpSocket::sentData);// send data
connect(tcpTemp,&myTcpSocket::disconnected,thread,&QThread::quit);// Thread exits when disconnected
tcpTemp->moveToThread(thread);// hold tcp Class moves to a new thread
thread->start();// The thread starts running
tcpClient->insert(socketDescriptor,tcpTemp);// Insert into the connection information
qDebug() <<"incomingConnection THREAD IS:" <<QThread::currentThreadId();
// Send connection signal
emit connectClient(tcpTemp->socketDescriptor(),tcpTemp->peerAddress().toString(),tcpTemp->peerPort());
}use moveToThread To handle moving to a new thread .
Other unimportant functions are not listed one by one , But don't forget to release the connection in the disconnected slot :
void MyTcpServer::setData(const QByteArray &data, const int handle)
{
emit sentData(data,handle);
}
void MyTcpServer::sockDisConnectSlot(int handle, QString ip, quint16 prot)
{
qDebug() <<"MyTcpServer::sockDisConnectSlot thread is:" << QThread::currentThreadId();
myTcpSocket * tcp = tcpClient->value(handle);
tcpClient->remove(handle);// Remove disconnected from connection management socket
delete tcp;// Release disconnected resources 、、 The sub object thread will also be released
emit sockDisConnect(handle,ip,prot);
}The second is inherited QTcpSocket Statement of , Go straight to the code :
// Inherit QTcpSocket To process the received data
class myTcpSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit myTcpSocket(qintptr socketDescriptor,QObject *parent = 0);
signals:
void readData(const int,const QString &,const quint16,const QByteArray &);// Send and get the data sent by the user
void sockDisConnect(const int ,const QString &,const quint16 );// Disconnected user information
public slots:
void thisReadData();// Processing received data
void sentData(const QByteArray & ,const int);// Slot for sending signals
private:
qintptr socketID;// preservation id,== this->socketDescriptor(); however this->socketDescriptor() The client disconnected and was released ,
// For disconnecting signals this->socketDescriptor() Cannot get the correct value
};This implementation is actually simpler 、、、 Attach the main signal slot connection part , Also, you need to pay attention to sending data , I am using Qt, Among them, the new syntax for signal slot , And they cooperate C++11 Of lambda expression , If you don't know C++11, You'd better go and have a look first C++11 Documents .
myTcpSocket::myTcpSocket(qintptr socketDescriptor, QObject *parent) :
QTcpSocket(parent),socketID(socketDescriptor)
{
this->setSocketDescriptor(socketDescriptor);
// Convert the system signal to the data we need to send 、、 Direct use lambda The expression ,qdebug Is to output thread information
connect(this,&myTcpSocket::readyRead,this,&myTcpSocket::thisReadData); // Connect to the processing function that receives the data
connect(this,&myTcpSocket::readyRead, // Convert the received information , Sending signal
[this](){
qDebug() <<"myTcpSocket::myTcpSocket lambda readData thread is:" << QThread::currentThreadId(); emit readData(socketID,this->peerAddress().toString(),this->peerPort() ,this->readAll());// Send the data sent by the user
});
connect(this,&myTcpSocket::disconnected, // Disconnected signal conversion
[this](){
qDebug() <<"myTcpSocket::myTcpSocket lambda sockDisConnect thread is:" << QThread::currentThreadId(); emit sockDisConnect(socketID,this->peerAddress().toString(),this->peerPort());// Send disconnected user information
});
qDebug() << this->socketDescriptor() << " " << this->peerAddress().toString()
<< " " << this->peerPort() << "myTcpSocket::myTcpSocket thread is " <<QThread::currentThreadId();
}
void myTcpSocket::sentData(const QByteArray &data, const int id)
{
// If it is the server, judge it well , Call directly write There will be cross thread phenomenon , So the server uses broadcast , Each connection determines whether it is the information it wants to send .
if(id == socketID)// Judge whether it is this socket Information about
{
qDebug() << "myTcpSocket::sentData" << QThread::currentThreadId();
write(data);
}
}In the whole code n individual qDebug() << , This is what I set to view the thread where it runs , These are useless in practical application 、、 Delete it yourself 、、 I still keep the examples and source code tested by myself 、、 After all, I forgot it for a long time , Keep it for that day and it will be clear at a glance 、、
Each connection is assigned a thread , Too many connections consume resources 、、 You can change it yourself , Move multiple connections to one thread , But then , You need to save thread information , Be more careful when allocating and releasing threads 、、 You can do it yourself 、、 I also welcome you to discuss 、、
Latest updates : Add thread management class ( It should be a thread pool ), Singleton class . You can preset the number of threads or how many connections each thread handles . The main change of the original code is the update of the new disconnection 、、 See code for details .
All code test examples , Server and client , I sent it to my github Yes , Attach project address :GitHub - dushibaiyu/QtTcpThreadServer: QtTcpThreadServer
Welcome to share , Please indicate the source and author when reprinting 、、 thank you 、、、
边栏推荐
- Language AI originally knew whether his answer was correct! New research in Berkeley and other universities is hot, netizen: dangerous, dangerous, dangerous
- 基本的unix域协议编程
- layoutgan:generating graphic layouts with wiregrame discriminators
- 6、 JMeter timer
- 312312dd
- 【深度学习】《动手学深度学习》环境配置
- static变量看着有点晕,gdb汇编清醒清醒
- Description of common operators in Halcon 3D
- DzzOffice_flowplayer播放器更改
- Mysql5.7 create user error: error 1364 (HY000): field 'SSL_ Cipher 'doesn't have a default value solution
猜你喜欢

constrained graphic layout generation via latent optimization

Efcore - entry and attach

Sword finger offer 10- I. Fibonacci sequence

五、jmeter脚本的基本构成&断言

电脑如何恢复已删除文件 如何恢复被删除的数据

Dual position relay dls-5/1

MySQL 高级原理: MySQL执行过程及执行顺序

How to customize an annotation?

Zhongang Mining: Fluorite guarantees the supply of fluorine in new energy industry
![Luogu_ P3383 [template] linear sieve prime number_ Euclidean sieve prime number](/img/f1/951293052e976639c8471933fe3592.png)
Luogu_ P3383 [template] linear sieve prime number_ Euclidean sieve prime number
随机推荐
Sword finger offer 10- I. Fibonacci sequence
静态路由技术
语言AI原来知道自己的回答是否正确!伯克利等高校新研究火了,网友:危险危险危险...
gan网络学习笔记
QTcpServer多线程实现
Sword finger offer 18 Delete the node of the linked list
Exploratory software testing
[TinyML]NetAug:Network Augmentation for Tiny Deep Learning
Halcon 3D create_ pose
探索式软件测试
EXCEL,选择数据如何选择合适的图表?
软件测试月薪28K大厂面试题 (经面试官允许可以拿走试卷)
众昂矿业:萤石保障新能源工业氟元素供应
QA robot section 1 - Introduction
Clickhouse (04) how to build a Clickhouse cluster
How to restore the files deleted from the U disk
MySQL 窗函数 流动平均数 running average
constrained graphic layout generation via latent optimization
DzzOffice_ Flowplayer player changes
2.4_9 Mysql 按分隔符,行转列