gpt4 book ai didi

c++ - 如何在Qt中编写客户端-服务器应用程序和实现简单的协议(protocol)

转载 作者:塔克拉玛干 更新时间:2023-11-03 00:25:08 25 4
gpt4 key购买 nike

也许这是个愚蠢的问题,实际上它很有吸引力,或者 Qt 对我来说太复杂了。事情是这样的:我在编写客户端-服务器应用程序时习惯了 java,它非常简单。我想在 C++ 中做同样的事情(我对 C++ 本身非常熟悉),我选择学习 Qt。我尝试用 qt 编写一些应用程序,但部分成功。

首先困扰我的是信号和槽。我知道如何在 GUI 编程中使用它们,但它让我对网络感到困惑。而且阻塞有问题。当我在 java 中调用 BufferedReader 的 readLine() 方法时,它会阻塞,直到它从套接字连接接收到行。在 Qt 中,我必须确保每次都有行可用,并在没有行时进行处理。

当我将 QSocket 的错误信号连接到我的一些自定义槽时,信号在服务器发送最后一行并关闭连接时发出,而在客户端的槽/函数中读取我从未读过最后一行。这是我目前遇到的一些问题。

当我不得不实现最简单的协议(protocol)时,插槽和检查是否有可用数据让我感到困惑。

重要部分:

我试图在互联网上找到好的例子,但问题是所有的例子都太复杂了。有没有人可以告诉我如何编写简单的客户端-服务器应用程序。服务器只接受一个客户端。客户端发送包含命令的文本行。如果命令是“ADD”或“SUB”,服务器发送“SUP”表示支持该命令。否则它发送“UNS”并关闭连接。如果客户端收到“SUP”,它会发送到更多行,其中包含要减去或添加的数字。服务器响应结果并关闭连接。

我知道 C++ 需要更多编码,但在 Java 中这只需要 5 分钟,所以用 C++ 编写它也不会花很长时间。

我相信这个例子对任何想在 Qt 中学习网络的人都非常有值(value)。

编辑:这是我尝试制作的应用程序(如上所述):这是服务器部分:

 #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();
}

这是客户端( header 与服务器的 header 类似,所以我不会发布):

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();
}
  1. 我可以做得更好吗?
  2. 在类似情况下有哪些好的做法?
  3. 当使用阻塞(不是信号/槽机制)时,当另一方关闭连接时处理事件的最佳方式是什么?
  4. 有人可以重写它以使其看起来更专业吗(我只是想看看它应该是什么样子,因为我认为我的解决方案远非完美)?
  5. 有人可以使用信号和槽重写这个吗?

谢谢。对不起我的英语,可能还有愚蠢:)

最佳答案

使用 Qt 联网并不难。

两点之间的通信由一个类处理;在 TCP/IP 的情况下,这将是 QTcpSocket 类。客户端和服务器都将与 QTcpSocket 对象进行通信。

与服务器的唯一区别是您从 QTcpServer 对象开始并调用 listen() 来等待连接...

QTcpServer* m_pTcpServer = new QTcpServer

//create the address that the server will listen on
QHostAddress addr(QHostAddress::LocalHost); // assuming local host (127.0.0.1)

// start listening
bool bListening = m_pServer->listen(addr, _PORT); //_PORT defined as whatever port you want to use

当服务器接收到来自客户端 QTcpSocket 的连接时,它会通过 newConnection 信号通知您,因此假设您已经连接到您自己类中的套接字以接收该信号,我们可以获取服务端的QTcpSocket对象来与客户端通信...

QTcpSocket* pServerSocket = m_pServer->nextPendingConnection();

服务器将为每个建立的连接接收一个 QTcpSocket 对象。服务器套接字现在可用于将数据发送到客户端套接字,使用 write 方法...

pServerSocket->write("Hello!");

当套接字(客户端或服务器)接收到数据时,它会发出readyRead 信号。因此,假设您已经连接到套接字的 readyRead 信号,槽函数可以检索数据...

QString msg = pSocket->readAll();

您需要的其他代码是处理连接、断开连接和错误信号,您应该连接相关插槽以接收这些通知。

确保仅在知道已建立连接时才发送数据。通常,我会让服务器接收连接并将“hello”消息发送回客户端。一旦客户端收到消息,它就知道它可以发送到服务器。

当任何一方断开连接时,剩余的一方将收到断开连接信号并可以采取适当的行动。

对于客户端,它只有一个 QTcpSocket 对象,在调用 connectToHost 之后,如果连接成功,您将收到一个connected 信号,或者错误信号。

最后,如果您只是想在同一台机器上的进程之间进行通信,您可以以相同的方式使用 QLocalServer 和 QLocalSocket。

关于c++ - 如何在Qt中编写客户端-服务器应用程序和实现简单的协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18722925/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com