2016-06-17 28 views
0

私は以下のコードをすべて提供しました。私がQtの初心者であることを忘れないでください。これはすばやく汚れた例です。QThreadでQTcpServerを作成し、メインスレッドからQTcpServerを作成する方法

私がしたいのは、QTcpServerリスナーを管理するQThreadを作成することです。私はそれが停止したときにリスナーを閉じて、再び起動したときにリスナーを開くことができるようにしたい。リスナーが今すぐ流出している可能性があることを無視してください。後でその問題に取り組みます。

私は、Stopが呼び出されたときに、それが作成されたスレッドとは別のスレッド(メインスレッドから呼び出されたスレッド)上でm_listener-> close()メソッドを呼び出す(TcpServerThreadで作成された) 。だから問題は、私はそれを修正する方法ですか?それを再設計してこの問題を回避する方法は?

これは完全なデザインではありません。私は実物を模倣するおもちゃの例を作っています。

tcpserverthread.h

#ifndef TCPSERVERTHREAD_H 
#define TCPSERVERTHREAD_H 

#include <QObject> 
#include <QThread> 

class QTcpServer; 

class TcpServerThread : public QThread 
{ 
    Q_OBJECT 
public: 
    TcpServerThread(); 

    void run(); 

    void Start(); 
    void Stop(); 
public slots: 
    void newConnection(); 

private: 

    QTcpServer* m_pListener; 
}; 

#endif // TCPSERVERTHREAD_H 

tcpserverthread.cpp

#include "tcpserverthread.h" 
#include "tcpserver.h" 
#include <iostream> 
#include <QTcpServer> 
#include <QTcpSocket> 
#include <QCoreApplication> 

TcpServerThread::TcpServerThread() 
{ 

} 

void TcpServerThread::run() 
{ 
    std::cout << "thread started ..." << std::endl; 
    std::cout << "listener starting ..." << std::endl; 
    m_pListener = new QTcpServer(); 
    connect(m_pListener, SIGNAL(newConnection()), this, SLOT(newConnection())); 
    if(!m_pListener->listen(QHostAddress::Any, 1234)) 
    { 
     std::cout << "listener could NOT START - " << m_pListener->errorString().toStdString() << std::endl; 
    } 
    else 
    { 
     std::cout << "listener SUCCESSFULLY STARTED" << std::endl; 
    } 

// std::cout << "thread running..." << std::endl; 
// m_pListener = new TcpServer(); 
// m_pListener->Start(); 

    exec(); 
} 

void TcpServerThread::newConnection() 
{ 
    qDebug() << "in new conn ... "; 
    //std::cout << "in new conn.." << std::endl; 
    QTcpSocket *soc = m_pListener->nextPendingConnection(); 
    soc->write("hello client"); 
} 

void TcpServerThread::Start() 
{ 
    start(); 
} 

void TcpServerThread::Stop() 
{ 
    std::cout << "TcpServer Stopping . . . " << std::endl; 
    //this close is the line that causes the problem... 
    m_pListener->close(); 
    this->quit(); 
} 

main.cppに

#include <QCoreApplication> 
#include <iostream> 
#include <QTcpServer> 
#include "tcpserver.h" 

#include "tcpserverthread.h" 

int main(int argc, char *argv[]) 
{ 
    QCoreApplication a(argc, argv); 

    TcpServerThread *t = new TcpServerThread(); 
    t->Start(); 
    t->Stop(); 

    return a.exec(); 
} 

あなたは、メインで>停止をT-するための呼び出しをコメントアウトすることができた場合それを実行し、telnet(またはパテ)を使用して@ 127.0.0.1:1234に接続します。

私はそれを停止させてから再開するようにしたいと思うし、接続がうまくいきます。

+0

私は、あなたが 'start'関数を呼び出す' Start'関数を作ったのを見ています。私は危険に暮らしたい:o – thuga

答えて

2

ここで間違った方法でQThreadを使用するつもりです。 QThreadから継承する場合は、スレッド化の機能を拡張したいからです。これはあなたが望むものではありません。

QThreadはスレッドを制御するためのクラスであり、あなたのためにクラスの一部であってはなりません。代わりに、スレッド要素を削除するだけで、クラスTcpServerTcpServerThreadではなく)を設計する必要があります。次に、run()、start()、stop()スロットを作成します。また、信号とスロットを使用するには、QObjectから継承する必要があります。このような何か:あなたのスレッドや、あなたのクラスを作成し、スレッドにあなたのクラスを移動することができ、メインで次に

class TcpServer: public QObject 
{ 
    Q_OBJECT // don't forget this 
    : 
    : 
} 

:あなたのスタート/ストップを呼び出すよう

TcpServer *pTcpServer = new TcpServer(); 
QThread *pThread = new QThread; 
pTcpServer->moveToThread(pThread); 
// Connect thread start to your run() function 
connect(pThread, &QThread::started, pTcpServer, &TcpServer::run, Qt::QueuedConnection); 
// Now run your thread, when it starts your run() slot will be called 
thread->start(); 

- 何が引き金起動停止?私はいくつかの他のオブジェクトを開始/停止するサーバー、またはいくつかのイベントを想定していますか?いずれにせよ、あなたは同じ方法でそれらを接続します。

connect(pSomeClass, &SomeClass::startTcpServer, pTcpServer, &TcpServer::start, Qt::QueuedConnection); 
connect(pSomeClass, &SomeClass::stopTcpServer, pTcpServer, &TcpServer::stop, Qt::QueuedConnection); 

ノート

私はあなたが(あなたのクラスに直接関数を呼び出しているので、あなたがメインスレッドで作成されたいくつかのオブジェクトを見ている理由だと思いますstart()/stop())。これをスレッド「境界」全体で行うことは、呼び出したスレッド(メインスレッド)内で実行されるアクション(または割り当てられたオブジェクト)が実行されるため安全ではありません。スロット/シグナルメカニズム(またはその他のスレッドセーフメカニズム)を使用する必要があります。

+0

QTcpServerオブジェクトをQThreadクラスから外すことを避けることを望んでいたのは、できるだけ小さな変更をしたいからだ。しかし、それを避けることができるようには見えません。なぜなら、私はそれを青い百万の異なる方法で試して、何か働くことができないからです。私が投稿したコードのようなデザインを使って動作させる方法を知っていれば、私は不思議に思います。 どちらの方法でも、私はあなたが与えたデザインを使ってサンプルアプリで作業するようになりました。ありがとう、code_fodder。私はそれを避ける方法は見当たらないので、実際にこのように再設計していきます。思考? – cchampion

+0

投稿したコードで作業できると思います。しかし、あなたはいくつか変更する必要があります:まず第一に、おそらく最も重要なことは、 't-> start();'以外のクラスで直接関数を呼び出さないでください。 t-> start()を呼び出すと、 'run()'が呼び出されます。個人的に私は 'run()'を変更しません。つまり、あなたが持っているものをオーバーロードして、コードを取り出して 'startup()'などのスロットに移動し、 'Stop()'関数をスロットにします。ここからあなたのスレッドオブジェクトと通信するためにスロット/シグナルを使用します。 –

+0

あなたのコードで 't-> Stop()'を呼び出すと、サーバスレッドではなく呼び出し元のスレッドでStop()コードを実行していることを直接意味します。これはスレッドセーフではないため、あなたの問題(または少なくとも1つの理由)を得る理由です。あなたはそれをしてはいけないので、そのようなことをスロット/信号で置き換えてください。 –

関連する問題