我正在将服务器编写为Qt控制台应用程序。我将服务器设置为等待套接字连接,但我还需要允许用户将命令输入服务器以进行管理。两者都是独立工作的。但是,我遇到的问题是,当我在while循环中接受并处理输入命令时,服务器不接受连接。
我有一个Socket类,在它的构造函数中,我有:
connect(server,SIGNAL(newConnection()),this, SLOT(newConnection()));
在构造函数的正下方,我调用一个具有更深入版本的函数来获取用户的命令:
QTextStream qin(stdin, QIODevice::ReadOnly);
QString usrCmd;
while(usrCmd != "exit" && usrCmd != "EXIT") {
//Get command input and process here
}
在newConnection()中,我只接受下一个连接,然后使用套接字。
QTcpSocket *serverSocket = server->nextPendingConnection();
我如何才能使套接字等待连接和同时等待用户输入的命令?
答案 0 :(得分:2)
您的代码问题是因为您使用while循环阻止事件循环。因此,您的问题的解决方案是异步读取标准输入。在Linux(在Mac上,我猜),根据各种互联网资源,您可以使用QSocketNotifier
通知数据何时到达stdin,并手动阅读。
当我使用Windows时,我建议你这样做(这应该适用于所有平台):
所以,这是伪代码。 MainAppClass应该是您现有的服务器类,只需编辑构造函数以创建新线程,并添加新槽以处理数据。
class Reader: public QThread
{
Q_OBJECT
public:
Reader(QObject * parent = 0 ): QThread(parent){}
void run(void)
{
forever{
std::string data;
std::getline (std::cin, data);
if(data == "exit")
{
emit exitServer();
return;
}
emit dataReady(QString::fromStdString(data));
}
}
signals:
void dataReady(QString data);
void exitServer();
};
class MainAppClass: public QObject
{
Q_OBJECT
public:
MainAppClass()
{
Reader * tr = new Reader(this);
connect(tr, SIGNAL(dataReady(QString)), this, SLOT(processData(QString)));
connect(tr, SIGNAL(exitServer()), this, SLOT(exitServer()));
tr->start();
}
public slots:
void processData(QString data)
{
std::cout << "Command: " << data.toStdString() << std::endl;
}
void exitServer()
{
std::cout << "Exiting..." << std::endl;
}
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainAppClass myapp; //your server
app.exec();
return 0;
}
由于我编写了如何使用QTcpSocket的简单指南,这里有简要介绍
当您获得客户端QTcpSocket
时,将readyRead()
信号连接到某个插槽,并从sender()
对象读取数据。您不需要在构造函数中读取任何内容。
阅读时,您可以使用标准QIODevice
功能。
注意:这是伪代码,您可能需要更改一些内容(在读取时检查流的状态,将指针保存到某些列表中的套接字,订阅disconnected()
signal,在构造函数中调用listen()
,检查QTcpServer
是否正在侦听等。)
因此,您需要在您的课程中使用插槽onReadyRead()
,其中包含以下代码:
void Server::readyReadSlot()
{
QTcpSocket *client = (QTcpSocket*)sender(); // get socket which emited the signal
while(client->canReadLine()) // read all lines!
// If there is not any lines received (you may not always receive
// whole line as TCP is stream based protocol),
// you will not leave data in the buffer for later processing.
{
QString line = client->readLine();
processLine(line); // or emit new signal if you like
}
}
在newConnection()
内,您需要将readyRead()
信号与您的广告连接。
void Server::newConnection()
{
QTcpSocket *clientSocket = server->nextPendingConnection();
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(readyReadSlot()));
}