问题描述
也许这是愚蠢的问题,实际上它的吸引力,或Qt只是为我复杂。
这里是事情:
当我编写客户端 - 服务器应用程序时,我用于java,它很简单。我想在C ++中做同样的事情(我非常熟悉C ++本身),我选择学习Qt。我试图在qt中写一些应用程序,但部分成功。
首先,困扰我的是信号和槽。我知道如何使用它们在GUI编程,但它困惑我与网络。有阻塞的问题。当我在Java中调用BufferedReader的readLine()方法时,它阻塞,直到它从套接字连接接收到行。在Qt中,我必须确保每次都有线路,并且在没有线路时处理。
当我将QSocket的错误信号连接到我的某些自定义插槽,当服务器发送最后一行并关闭连接时发出信号,并且在客户端的插槽/函数中读取我从未读取最后一行。这是我到目前为止遇到的一些问题。
插槽和检查是否有可用的数据使我困惑,当我不得不实现最简单的协议。
重要部分:
我试图在互联网上找到很好的例子,但问题是所有的例子都是复杂的。有没有人怎么能告诉我如何写简单的客户端 - 服务器应用程序。服务器只接受一个客户端。客户端发送包含命令的文本行。如果命令为ADD或SUB,服务器发送SUP表示支持命令。否则,它发送UNS并关闭连接。如果客户端接收到SUP,它发送到包含要减去或添加的数字的更多行。服务器响应结果并关闭连接。
我知道C ++需要更多的编码,但在Java中这只需要5分钟,因此不应该花费很长时间
我相信这个例子对任何想要在Qt中学习网络的人都是很有价值的。
edit:
这是我尝试创建应用程序(如上所述):
这里是服务器部分:
#ifndef TASK_H
#define TASK_H
#include< QObject>
#include< QTcpServer>
class任务:public QObject
{
Q_OBJECT
public:
任务(QObject * parent = 0):QObject
$ b public slots:
void run();
void on_newConnection();
void on_error(QAbstractSocket :: SocketError);
信号:
void finished();
private:
QTcpServer服务器;
};
#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()< 听;
} else {
qDebug()<< 不能听;
qDebug()<< server.errorString();
}
}
void Task :: on_newConnection(){
std :: cout< handeling new connection ... \\\
;
QTcpSocket * socket = server.nextPendingConnection();
QTextStream tstream(socket);
while(!socket-> canReadLine()){
socket-> waitForReadyRead(( - 1));
}
QString operation = tstream.readLine();
qDebug()<< dbg:<<操作;
if(operation!=ADD&& operation!=SUB){
tstream< UNS\\\
;
tstream.flush();
socket-> disconnect();
return;
}
tstream<< SUP\\\
;
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<< \\\
;
tstream.flush();
qDebug()<< 结果是:< r;
socket-> disconnect();
}
void Task :: on_error(QAbstractSocket :: SocketError){
qDebug()< 服务器错误;
server.close()
}
这是客户端(标头类似于服务器所以我不会张贴) :
void Task :: run()
{
QTcpSocket插座;
std :: string temp;
socket.connectToHost(QHostAddress :: LocalHost,9000);
if(socket.waitForConnected(-1))
qDebug()<< 连接的;
else {
qDebug()<< 无法连接;
return;
}
QTextStream tstream(& socket);
QString op;
std :: cout<< operation:;
std :: cin>>温度
op = temp.c_str();
tstream<< op<< \\\
;
tstream.flush();
qDebug()<< dbg:<< op<< \\\
;
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString response = tstream.readLine();
qDebug()<< dbg:<<响应;
if(response ==SUP){
std :: cout< operand 1:;
std :: cin>>温度
op = temp.c_str();
tstream<< op +\\\
;
std :: cout<< operand 2:;
std :: cin>>温度
op = temp.c_str();
tstream<< op +\\\
;
tstream.flush();
while(!socket.canReadLine()){
socket.waitForReadyRead(-1);
}
QString result = tstream.readLine();
std :: cout<< qPrintable(result is:+ result);
} else if(response ==UNS){
std :: cout< 不支持的操作。
} else {
std :: cout<< 未知错误。;
}
emit finished();
}
- 我能做得更好吗? >
- 在类似情况下,一些好的做法是什么?
- 当使用阻塞(不是信号/槽机制)时,什么是处理事件的最佳方式关闭连接?
- 有人可以重写这个来使它看起来更专业(我只是看看它应该是什么样子,因为我认为我的解决方案远非完美)?
- 有人可以使用信号和广告位重写此信息吗?
对不起我的英语,可能是愚蠢:)
与Qt的网络不是那么困难。
两点之间的通信由单个类处理;在TCP / IP的情况下,这将是QTcpSocket类。客户端和服务器都将与QTcpSocket对象进行通信。
与服务器的唯一区别是,您从QTcpServer对象开始,并调用listen()等待连接...
QTcpServer * m_pTcpServer = new QTcpServer
//创建服务器的地址listen on
QHostAddress addr(QHostAddress :: LocalHost); //假设本地主机(127.0.0.1)
//开始侦听
bool bListening = m_pServer-> listen(addr,_PORT); // _ PORT定义为要使用的任何端口
当服务器从客户端接收到连接时QTcpSocket ,它会通过一个 newConnection 信号通知你,所以假设你已经连接到你自己的类中的socket来接收该信号,我们可以得到服务器的QTcpSocket对象与客户端通信。 ..
QTcpSocket * pServerSocket = m_pServer-> nextPendingConnection();
服务器将为每个连接接收一个QTcpSocket对象。现在可以使用 方法将服务器套接字发送到客户端套接字...
pServerSocket-> write(Hello!);
当套接字(客户端或服务器)接收数据时,会发出 readyRead
QString msg = pSocket-> readAll();
您需要的另一个代码是处理连接,断开连接和错误信号,请连接用于接收这些通知的相关插槽。
确保只有在知道连接时才发送数据。通常,我会让服务器接收一个连接并发送一个hello消息给客户端。一旦客户端接收到该消息,它就知道它可以发送到服务器。
当任一端断开连接时,剩余端将接收到断开信号并可以适当地执行。 / p>
对于客户端,它只有一个QTcpSocket对象,并且在调用 connectToHost 后,您将收到连接的
最后,您可以使用QLocalServer和QLocalSocket以相同的方式,如果连接成功,你只是试图在同一台机器上的进程之间进行通信。
Maybe this is stupid question, actually it's appeal, or Qt is just to complicated for me.Here's the thing:I'm used to java when writing client-server application, and it's very simple. I would like to do same things in C++ (I'm very familiar with C++ itself), and I choose to learn Qt. I tried to write some applications in qt, but with partial success.
First thing that bothers me is signals and slots. I know how to use them in GUI programming but it confuses me with networking. And there's problem with blocking. When I call BufferedReader's readLine() method in java it blocks until it receives line from socket connection. In Qt I must make sure that there is line available every time, and handle it when there isn't one.
And when I connect QSocket's error signal to some of my custom slots, the signal is emitted when server sends last line and closes the connection, and in client's slot/function that reads I never read that last line. That are some problems I faced so far.
Slots and checking if there is data available makes me confused when I had to implements even the simplest protocols.
Important part:
I tried to find good example on the internet, but problem is that all examples are to complicated an big. Is there anyone how can show me how to write simple client-server application. Server accepts only one client. Client sends textual line containing command. If command is "ADD" or "SUB", server sends "SUP" indicating that command is supported. Otherwise it sends "UNS" and closes the connection. If client receives "SUP" it sends to more lines containing numbers to be subtracted or added. Server responds with result and closes connection.
I know that C++ requires more coding, but in Java this would take only 5 minutes, so it shouldn't take to long to write it in C++ either.
I'm sure this example would be very valuable to anyone who wants to learn networking in Qt.
edit:This is my try to make the application (described above):here is the server part:
#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();
}
This is client side (header is similar to server's so I wont post it):
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();
}
- What I could do better?
- What are some good practices in similar situations?
- When using blocking (not signal/slot mechanism), what is the best way to handle event when other side closes the connection?
- Can someone rewrite this to make it look more professional (I just what to see how it supposed to look like, because I think that my solution is far from perfect) ?
- Can someone rewrite this using signals and slots?
Thanks you.Sorry for my English, and probably stupidity :)
解决方案 Networking with Qt is not that difficult.
Communication between two points is handled by a single class; in the case of TCP/IP, that would be the QTcpSocket class. Both the client and server will communicate with a QTcpSocket object.
The only difference with the server is that you start with a QTcpServer object and call listen() to await a connection...
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
When the server receives a connection from a client QTcpSocket, it will notify you with a newConnection signal, so assuming you've made a connection to a socket in your own class to receive that signal, we can get the server QTcpSocket object to communicate with the client...
QTcpSocket* pServerSocket = m_pServer->nextPendingConnection();
The server will receive a QTcpSocket object for each connection made. The server socket can now be used to send data to a client socket, using the a write method...
pServerSocket->write("Hello!");
When a socket (either client or server) receives data, it emits the readyRead signal. So, assuming you have made a connection to the readyRead signal for the socket, a slot function can retrieve the data...
QString msg = pSocket->readAll();
The other code you'll need is to handle the connect, disconnect and error signals, which you should connect relevant slots for receiving these notifications.
Ensure you only send data when you know the connection has been made. Normally, I would have the server receive a connection and send a 'hello' message back to the client. Once the client receives the message, it knows it can send to the server.
When either side disconnects, the remaining side will receive the disconnect signal and can act appropriately.
As for the client, it will just have one QTcpSocket object and after calling connectToHost, you will either receive a connected signal if the connection was succesfully made, or the error signal.
Finally, you can use QLocalServer and QLocalSocket in the same way, if you're just trying to communicate between processes on the same machine.
这篇关于如何编写Client-Server应用程序并在Qt中实现简单协议的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!