多分これはばかげた質問かもしれませんが、実際には魅力的であるか、Qt は私にとって複雑すぎるだけです。ここに問題があります: 私はクライアント/サーバー アプリケーションを作成するときに Java に慣れており、それは非常に単純です。私は C++ で同じことをしたいと思っており (私は C++ 自体に精通しています)、Qt を学ぶことにしました。Qt でいくつかのアプリケーションを作成しようとしましたが、部分的に成功しました。
最初に気になるのはシグナルとスロットです。GUI プログラミングでそれらを使用する方法は知っていますが、ネットワークで混乱します。そして、ブロックに問題があります。java で BufferedReader の readLine() メソッドを呼び出すと、ソケット接続から行を受信するまでブロックされます。Qt では、利用可能な回線が毎回あることを確認し、回線がない場合はそれを処理する必要があります。
また、QSocket のエラー シグナルをカスタム スロットの一部に接続すると、サーバーが最後の行を送信して接続を閉じたときにシグナルが送信されます。以上が私がこれまでに直面したいくつかの問題です。
スロットと利用可能なデータがあるかどうかのチェックは、最も単純なプロトコルでさえ実装しなければならなかったときに私を混乱させます.
重要な部分:
私はインターネットで良い例を見つけようとしましたが、問題はすべての例が非常に複雑であることです。シンプルなクライアントサーバーアプリケーションの書き方を教えてくれる人はいますか? サーバーは 1 つのクライアントのみを受け入れます。クライアントは、コマンドを含むテキスト行を送信します。コマンドが「ADD」または「SUB」の場合、サーバーはコマンドがサポートされていることを示す「SUP」を送信します。それ以外の場合は、「UNS」を送信して接続を閉じます。クライアントが「SUP」を受信すると、減算または加算する数値を含む複数の行に送信します。サーバーは結果を返し、接続を閉じます。
C++ ではより多くのコーディングが必要であることはわかっていますが、Java ではこれに 5 分しかかからないため、C++ で記述するのにもそれほど時間はかからないはずです。
この例は、Qt でネットワークを学びたい人にとって非常に価値があると確信しています。
編集: これはアプリケーションを作成しようとする私の試みです(上記で説明):ここにサーバー部分があります:
#ifndef TASK_H
#define TASK_H
#include <QObject>
#include <QTcpServer>
class Task : public QObject
{
Q_OBJECT
public:
Task(QObject *parent = 0) : QObject(parent) {}
public slots:
void run();
void on_newConnection();
void on_error(QAbstractSocket::SocketError);
signals:
void finished();
private:
QTcpServer server;
};
#endif // TASK_H
void Task::run()
{
connect(&server,SIGNAL(newConnection()),this,SLOT(on_newConnection()));
connect(&server,SIGNAL(acceptError(QAbstractSocket::SocketError)),this,SLOT(on_error(QAbstractSocket::SocketError)));
if(server.listen(QHostAddress::LocalHost, 9000)){
qDebug() << "listening";
}else{
qDebug() << "cannot listen";
qDebug() << server.errorString();
}
}
void Task::on_newConnection(){
std::cout << "handeling new connection...\n";
QTcpSocket* socket = server.nextPendingConnection();
QTextStream tstream(socket);
while(!socket->canReadLine()){
socket->waitForReadyRead((-1));
}
QString operation = tstream.readLine();
qDebug() << "dbg:" << operation;
if(operation != "ADD" && operation != "SUB"){
tstream << "UNS\n";
tstream.flush();
socket->disconnect();
return;
}
tstream << "SUP\n";
tstream.flush();
double op1,op2;
while(!socket->canReadLine()){
socket->waitForReadyRead((-1));
}
op1 = socket->readLine().trimmed().toDouble();
qDebug() << "op1:" << op1;
while(!socket->canReadLine()){
socket->waitForReadyRead(-1);
}
op2 = socket->readLine().trimmed().toDouble();
qDebug() << "op2:" << op2;
double r;
if(operation == "ADD"){
r = op1 + op2;
}else{
r = op1 - op2;
}
tstream << r << "\n";
tstream.flush();
qDebug() << "result is: " << r;
socket->disconnect();
}
void Task::on_error(QAbstractSocket::SocketError ){
qDebug() << "server error";
server.close();
}
これはクライアント側です (ヘッダーはサーバーのものと似ているので投稿しません):
void Task::run()
{
QTcpSocket socket;
std::string temp;
socket.connectToHost(QHostAddress::LocalHost,9000);
if(socket.waitForConnected(-1))
qDebug() << "connected";
else {
qDebug() << "cannot connect";
return;
}
QTextStream tstream(&socket);
QString op;
std::cout << "operation: ";
std::cin >> temp;
op = temp.c_str();
tstream << op << "\n";
tstream.flush();
qDebug() << "dbg:" << op << "\n";
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString response = tstream.readLine();
qDebug() << "dbg:" << response;
if(response == "SUP"){
std::cout << "operand 1: ";
std::cin >> temp;
op = temp.c_str();
tstream << op + "\n";
std::cout << "operand 2: ";
std::cin >> temp;
op = temp.c_str();
tstream << op + "\n";
tstream.flush();
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString result = tstream.readLine();
std::cout << qPrintable("result is: " + result);
}else if(response == "UNS"){
std::cout << "unsupported operatoion.";
}else{
std::cout << "unknown error.";
}
emit finished();
}
- もっとうまくできることはありますか?
- 同様の状況での優れたプラクティスは何ですか?
- (シグナル/スロットメカニズムではなく) ブロッキングを使用する場合、反対側が接続を閉じたときにイベントを処理する最良の方法は何ですか?
- 誰かがこれを書き直して、よりプロフェッショナルに見えるようにすることはできますか?
- 誰かがシグナルとスロットを使ってこれを書き直すことができますか?
ありがとうございます。私の英語で申し訳ありませんが、おそらく愚かです:)