一、前言
在网络编程中,处理大量并发连接是一项挑战。为了提高服务器的性能,特别是在高并发场景下,使用多线程来处理客户端连接是一种常见的策略。本篇文章将介绍如何使用 Qt 框架,在 C++ 中实现一个支持多线程的高并发服务器。
为什么需要重写 incomingConnection()
?
1.incomingConnection()
是处理新客户端连接的入口点。当有新连接时,Qt 会调用该方法并传递一个 socketDescriptor
(套接字描述符)。默认情况下,QTcpServer
并不会自动为每个连接创建和处理新的 QTcpSocket
实例。重写 incomingConnection()
允许我们自定义如何处理新连接,包括为每个连接创建新的 QTcpSocket
或自定义的处理类(如 ClientHandler
)。
2.在高并发场景下,为了防止单线程阻塞导致性能问题,需要将每个客户端的处理逻辑放到一个单独的线程中。通过重写 incomingConnection()
,我们可以在接受到新的客户端连接时,为其创建一个新的线程并在其中处理客户端的请求。
3.通过重写 incomingConnection()
,可以更好地管理客户端连接的生命周期。
二、项目结构
ClientHandler
:用于处理每个客户端连接的类。TCPServer
:继承自QTcpServer
,用于管理客户端连接的服务器类。QtEthernetServer
:提供服务器初始化及启动的接口。
三、代码实现
1. ClientHandler
类
ClientHandler
类负责处理单个客户端的连接,包括读取数据和处理客户端断开连接的情况。
class ClientHandler : public QObject
{
Q_OBJECT
public:
// ClientHandler(qintptr socketDescriptor, QObject* parent = nullptr);
void init(qintptr _socketDescriptor);
int conState()
{
if (socket->state() == QAbstractSocket::ConnectedState)
{
return 1;
}
else
{
return 0;
}
}
public slots:
void handleClient();
void onReadyRead();
void onDisconnected();
private:
QTcpSocket* socket;
qintptr socketDescriptor;
};
void ClientHandler::init(qintptr _socketDescriptor)
{
socketDescriptor = _socketDescriptor;
}
void ClientHandler::handleClient() {
socket = new QTcpSocket;
if (socket->setSocketDescriptor(socketDescriptor))
{
connect(socket, &QTcpSocket::readyRead, this, &ClientHandler::onReadyRead);
connect(socket, &QTcpSocket::disconnected, this, &ClientHandler::onDisconnected);
}
else {
delete socket;
socket = nullptr;
emit destroyed();
}
}
void ClientHandler::onReadyRead()
{
/*读取数据*/
}
void ClientHandler::onDisconnected() {
// 处理客户端断开连接的逻辑
}
2. TCPServer
类
TCPServer
类继承自 QTcpServer
,负责监听并接受新的客户端连接。每当有新的客户端连接时,TCPServer
会为其创建一个 ClientHandler
实例,并将其分配到一个新线程中处理。
class TCPServer : public QTcpServer
{
public:
ClientHandler* handler;
protected:
void incomingConnection(qintptr socketDescriptor) override;
};
void TCPServer::incomingConnection(qintptr socketDescriptor)
{
QThread* thread = new QThread;
handler = new ClientHandler();
handler->init(socketDescriptor);
handler->moveToThread(thread);
connect(thread, &QThread::started, handler, &ClientHandler::handleClient);
connect(handler, &ClientHandler::destroyed, thread, &QThread::quit);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
}
3. QtEthernetServer
类
QtEthernetServer
提供了服务器的初始化和启动方法。
void QtEthernetServer::init(QString strIp, int Port)
{
server = new TCPServer;
server->init();
server->setEthernetServer(q);
if (!server->listen(QHostAddress::Any, Port))
{
OiWarning() << "开启服务器失败...";
}
else
{
OiWarning() << "开启服务器...";
}
q->connect(server, SIGNAL(newConnection()), SLOT(onConnected()));
}
}
void QtEthernetServer::onConnected()
{
while (server->hasPendingConnections())
{
d->server->nextPendingConnection();
OiWarning() << "已经连接服务器...";
}
}