我正在为客户端/服务器应用程序编写客户端。客户端应该使用登录窗口登录。如果登录成功,则等待"窗口出现(这只是一个包含标签的窗口)。在服务器端,有一个等待n个客户端登录的屏障;当发生这种情况时,会播放一条消息,等待窗口应该关闭,并为每个客户端显示一个新窗口。
网络接口由我实现,使用低级功能,而不是Qt提供的功能。
实际的等待循环是这样的:
char buffer[256];
while (strcmp(buffer, "proceed"))
read(sockfd, buffer, 256);
问题在于,如果我在主线程中启动此循环,则应用程序会阻塞,原因很明显。
如何运行此循环而不阻止应用程序,并在对话结束时关闭对话框?
稍后编辑:我也尝试使用QThreads,但是,由于我还不完全理解的原因,该应用程序仍然崩溃:
class WaitLoop : public QThread {
public:
WaitLoop(NetworkHandler &network) : network(network) {}
private :
NetworkHandler &network;
void run() {
this->network.waitForGameStart();
}
};
在等待对话框构造函数中:
WaitLoop *waitLoop = new WaitLoop(network);
connect(waitLoop, SIGNAL(finished()), this, SLOT(gameStartSlot()));
waitLoop->start();
应用程序仍然使用此方法崩溃。
答案 0 :(得分:0)
解决这个问题的最方法是不使用低级函数,因为你不是用C语言编写的。至少使用QAbstractSocket
来包装sockfd
。 setSocketDescriptor
方法允许您这样做。
然后您的代码变为非阻塞和异步:
class Controller : public QObject {
Q_OBJECT
QStateMachine m_sm;
QState s_init{&m_sm}, s_proceeding{&m_sm};
QAbstractSocket m_socket;
Q_SIGNAL void proceed();
Q_SLOT void onData() {
auto data = m_socket.readAll();
if (data.contains("proceed")) proceed();
}
public:
Controller(QObject * parent = 0) : QObject(parent) {
connect(&m_socket, &QIODevice::readyRead, this, &Controller::onData);
s_init.addTransition(this, &Controller::proceed, &s_proceeding);
m_sm.setInitialState(&s_init);
m_sm.start();
}
bool setup(quintptr fd) {
return m_socket.setSocketDescriptor(fd);
}
};
通过使用状态机,可以轻松添加更多状态,对其转换做出反应(请参阅QState::onEntry
信号等),并确保行为正确。充实UML状态图迫使您考虑处理角落案例等。有关完整示例,请参阅this answer。