2011-08-15 21 views
0

threaded fortune-serverをQtの例から修正しました。 クライアントはサーバーに接続し、次にヘッダーを送信して認証します。QTcpSocketからデータを読み込む際の問題

tcpSocket = new QTcpSocket(); 
tcpSocket->connectToHost(addr, port); 
QByteArray block = "someheader"; 
int x = tcpSocket->write(block); 
qDebug() << x; 

クライアントは、ここではOKらしいとqDebugblockの実際のサイズを表示します。

サーバ側では、私はincomingConnectionをあらかじめ定義しておき、新しい接続ごとにスレッドを開始します。

void Server::incomingConnection(int socketDescriptor) { 
    const QString &str = vec[qrand() % vec.size()]; 
    SpellThread *thread = new SpellThread(socketDescriptor, str); 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    qDebug() << " -- incoming connection"; 
    thread->start(); 
} 

私はsockをチェックしてチェックすることがあります。

void SpellThread::run() { 
    qDebug() << " -- in spellthread"; 
    connect(sock, SIGNAL(readyRead()), this, SLOT(checkBytes())); 
    //.... 
    qDebug() << " -- end spellthread"; 
} 

最初の問題は、私はクライアントからのデータを送信していたときに、readyReadが発射されていないということである(sockはこちらQTcpServer*です)。

-- incoming connection 
-- in spellthread 
-- end spellthread 

クライアントは、ヘッダ長の実際のサイズを出力しているが: メッセージである(IはcheckBytesにデバッグメッセージを追加しました)。

第2の問題は、現在checkBytesが非常に悪い設計されていることです。まず、ヘッダーがOKであることを確認してフラグを設定し、メッセージのサイズを取得して別のフラグを設定し、最後に実際のメッセージを取得します。これは非常に不器用です。私はまず信号をエスケープしようとしましたが、代わりにsock->waitForReadyRead()を使用しました。ただし、常にfalseを返します。 (ドキュメントから: "カスタムデバイス用のブロッキングAPIを提供するためにこの関数を再実装する。デフォルトの実装は何もせず、falseを返す")。

Qtで複数のクライアントと複数の読み取り/書き込みを行うクライアント/サーバーアプリケーションを実際に作成するにはどうすればよいですか?アプリケーションの設計を改善し、現在の2つの問題を解決するための提案が本当に必要です。

答えて

2

スレッドまたはスロット内でイベントループを開始するためにQThread::exec()を呼び出すことなく、スロットまたはソケット信号をスレッドで使用することはできません。あなたのcheckBytesスロットがQThreadに属しているので

、それはスレッドによって実行されない

すでにあなたがやりたいように見える最も近い例はNetwork Chatである((QThreads hereについての詳細な記事があります)特に2つのクラスServerおよびConnection)。

----------
編集
あなたが(任意のスロットなし)のスレッドを使用する必要がある場合は、QTcpSocketオブジェクト必見あなたがwaitForReadyReadを呼び出すのと同じスレッドに属します。例えば、と:

SpellThread::SpellThread(int socketDescriptor, const QString & str) { 
    tcpSocket = new QTcpSocket(); // There should be no parent to be able 
            // to move it to the thread 
    tcpSocket->moveToThread(this); 
    ... 

あるいはそれは自動的にそのスレッドに属するようrun関数内QTcpSocketオブジェクトを作成することにより(それは簡単に幸運例で説明しました)。 QTcpSocketを動的に割り当てる場合や、親を持たない場合は、手動で削除する必要があります。

+0

クライアントが接続するときに多くの計算が必要となるため、スレッドが必要です。私はシグナルをまったく使用したくない - ちょうど新しいクライアントからいくつかのデータを読んでから、いくつかのデータを送り返したい。最終的にクライアントがデータを送信しない場合、タイムアウトになります。しかし、 'waitForReadyRead'はそのトリックを行わず常に失敗します。信号なしで私にいくつかの提案を教えてもらえますか? – Marii

+0

あなたのコメントを考慮に入れて私の答えを編集しました。 – alexisdm

+0

私は信号なしでバージョンを試しましたが、このコード行に問題がありました: 'while(sock.bytesAvailable()<4);'。私はソケットがバイトが来た時を知ることを期待しました。私はこれを以下のように変更しました: 'while(sock.bytesAvailable()<4)sock.waitForReadyRead();'そして今は問題ありません。あなたの答えをありがとう、私はそれを受け入れる。 :) – Marii

関連する問題