您的代码有问题是因为您使用 while 循环阻塞了事件循环。因此,您的问题的解决方案是异步读取标准输入。在 Linux 上(我猜在 Mac 上),您可以QSocketNotifier
根据各种 Internet 资源来通知数据何时到达标准输入,并手动读取它)。
当我使用 Windows 时,我建议您以这种方式进行(应该适用于所有平台):
- 打开从标准输入读取数据的线程
- 一旦你得到一些数据(也许是行?),你可以使用 Qt 信号槽机制将数据传递给主线程进行处理,而不会阻塞事件循环。
所以,这是伪代码。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()
信号、调用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()));
}