Mar*_*rko 5 c++ qt client-server sample
也许这是一个愚蠢的问题,实际上它的吸引力,或者Qt只是让我复杂化.事情就是这样:我在编写客户端 - 服务器应用程序时习惯了java,而且非常简单.我想在C++中做同样的事情(我对C++本身非常熟悉),我选择学习Qt.我尝试在qt中编写一些应用程序,但取得了部分成功.
困扰我的第一件事是信号和插槽.我知道如何在GUI编程中使用它们,但它让我对网络感到困惑.阻塞有问题.当我在java中调用BufferedReader的readLine()方法时,它会阻塞,直到它从套接字连接接收到行.在Qt我必须确保每次都有可用的行,并在没有行时处理它.
当我将QSocket的错误信号连接到我的一些自定义插槽时,当服务器发送最后一行并关闭连接时会发出信号,而在客户端的插槽/功能中,我从未读过最后一行.这是我到目前为止遇到的一些问题.
插槽和检查是否有可用的数据让我感到困惑,因为我必须实现最简单的协议.
重要部分:
我试图在互联网上找到一个很好的例子,但问题是所有的例子都是复杂的.有没有人可以告诉我如何编写简单的客户端 - 服务器应用程序.服务器只接受一个客户端.客户端发送包含命令的文本行.如果命令是"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();
}
Run Code Online (Sandbox Code Playgroud)
这是客户端(标题类似于服务器的所以我不会发布它):
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();
}
Run Code Online (Sandbox Code Playgroud)
谢谢.对不起,我的英文,可能是愚蠢的:)
与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
Run Code Online (Sandbox Code Playgroud)
当服务器从客户端QTcpSocket接收连接时,它会通过newConnection信号通知您,所以假设您已经连接到您自己的类中的套接字以接收该信号,我们可以让服务器QTcpSocket对象与之通信客户端...
QTcpSocket* pServerSocket = m_pServer->nextPendingConnection();
Run Code Online (Sandbox Code Playgroud)
服务器将为每个连接接收QTcpSocket对象.服务器套接字现在可用于使用write方法将数据发送到客户端套接字...
pServerSocket->write("Hello!");
Run Code Online (Sandbox Code Playgroud)
当套接字(客户端或服务器)接收数据时,它会发出readyRead信号.因此,假设您已连接到套接字的readyRead信号,则插槽函数可以检索数据...
QString msg = pSocket->readAll();
Run Code Online (Sandbox Code Playgroud)
您需要的其他代码是处理连接,断开连接和错误信号,您应该连接相关插槽以接收这些通知.
确保只有在知道已建立连接后才发送数据.通常,我会让服务器接收连接并向客户端发送"hello"消息.一旦客户端收到消息,它就知道它可以发送到服务器.
当任一侧断开时,剩余侧将接收断开信号并且可以适当地动作.
对于客户端,它只有一个QTcpSocket对象,在调用connectToHost之后,如果连接成功,您将收到连接的信号,或者错误信号.
最后,如果您只是尝试在同一台机器上的进程之间进行通信,则可以以相同的方式使用QLocalServer和QLocalSocket.