首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >多客户端TCP服务器,每个客户端和DB连接池都有一个线程。

问多客户端TCP服务器,每个客户端和DB连接池都有一个线程。
EN

Code Review用户
提问于 2017-11-25 19:46:35
回答 1查看 3.1K关注 0票数 1

我正在创建一个Qt (使用SSL)服务器,多个客户端应该连接并使用DB,这是主要任务。因此,我认为我可以使用这个架构:每个客户端都有自己的线程,客户端通过DB连接池使用DB。

客户端连接部分

main.cpp:

代码语言:javascript
复制
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    MyServer server;

    server.listen(QHostAddress::Any, 1234);

    return a.exec();
}

没药。h:

代码语言:javascript
复制
class MyServer : public QTcpServer
{
    Q_OBJECT

    explicit MyServer(QObject *parent = 0);
    ~MyServer();

protected:
    void incomingConnection(qintptr socketDescriptor) Q_DECL_OVERRIDE;

signals:
    void stopAll();
};

myserver.cpp:

代码语言:javascript
复制
MyServer::MyServer(QObject *parent) : QTcpServer(parent)
{
    //...
}

MyServer::~MyServer(){
    emit stopAll();
}

void MyServer::incomingConnection(qintptr socketDescriptor){
    QThread* clientThread = new QThread;
    MyClient *client = new MyClient(socketDescriptor, this);

    client->moveToThread(clientThread);

    connect(clientThread, SIGNAL(started()), client, SLOT(process()));

    connect(client, SIGNAL(finished()), clientThread, SLOT(quit()));
    connect(this, SIGNAL(stopAll()), client, SLOT(stopFromServer()));
    connect(client, SIGNAL(finished()), client, SLOT(deleteLater()));
    connect(clientThread, SIGNAL(finished()), clientThread, SLOT(deleteLater()));

    clientThread->start();
}

我的客户:

代码语言:javascript
复制
class MyClient : public QObject
{
    Q_OBJECT
public:
    explicit MyClient(int socketDescriptor, MyServer *server);
    ~MyClient();

private:
    QSslSocket* socket = NULL;

public slots:
    void process();
}

myclient.cpp:

代码语言:javascript
复制
void MyClient::process(){
    //typical connection things
    connect(this->socket, SIGNAL(encrypted()), this, SLOT(ready()));
}

void MyClient::ready(){
    connect(socket,SIGNAL(readyRead()),this, SLOT(newData()));
}

DB连接池部分

将在客户端线程中执行的DAO:

.cpp:

代码语言:javascript
复制
//DAO method

QList<QMap<QString, QString>> sqlResult = DatabaseService::executeQuery(sqlCommand);

//sqlResult processing

DatabaseService:

.h:

代码语言:javascript
复制
class DatabaseService
{
public:
    //...
    static QMap<QString, QString> executeQuery(QString command);

private:
    static QThreadStorage<QSqlDatabase> mDatabasePool;
    static QSqlDatabase getDatabase();

};

.cpp:

代码语言:javascript
复制
//...
QThreadStorage<QSqlDatabase> DatabaseService::mDatabasePool;

QSqlDatabase DatabaseService::getDatabase()
{
    if(DatabaseService::mDatabasePool.hasLocalData()) {
        return DatabaseService::mDatabasePool.localData();
    } else {
        auto database = QSqlDatabase::addDatabase("QPSQL", QUuid::createUuid().toString());
        database.setHostName("hostName");
        database.setDatabaseName("databaseName");
        database.setUserName("user");
        database.setPassword("password");
        database.open();
        DatabaseService::mDatabasePool.setLocalData(database);
        return database;
    }
}

QMap<QString,QString> DatabaseService::executeQuery(QString command){

    QSqlQuery query (DatabaseService::getDatabase());
    query.exec(command);

    //...

    return result;
}

//...

这是所有与主题相关的代码。

您还可以检查我关于DB连接池的SO问题(请注意代码不完全相同)。

这个建筑有多好?什么是可以修正和改进的,以及如何改进?

EN

回答 1

Code Review用户

发布于 2017-11-25 21:24:02

我不知道QThreads是如何工作的:

  • 它是OS线程的包装器吗?
  • QThreads集合了吗?

假设一个QThread是一个包装器,而不是池。

那么这个技术实际上是非常有限的。问题是线程的创建成本相对较高,实际上您可以同时运行其中的少数线程而不需要花费(创建超过2倍的处理器可能是个坏主意),在套接字编程中,大多数线程都是空闲的(网络比处理器的速度慢)。

在顶部的c10k上有一篇著名的论文。基本上,给定当前的网络速度和处理器速度,您应该能够很容易地支持10,000个同时连接。但是使用这个模型,您将支持几百个同时连接。

基本上,您希望围绕单个线程模型设计服务器,并使用pselect() (尽管现在更好的选项poll()、epoll()和最终LibEvent已经过时了)。不要费心尝试旧的版本,只需跳转到LibEvent。

票数 1
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/181303

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档