虽然,答案已经被接受了,我想和大家分享我的)
我从你的问题明白了什么:有256当前活动连接,您不时发送一个请求(命名为“command”)给其中一个请求并等待响应。同时,要进行这个过程中多线程和,虽然你说:“这需要阻塞,直到它获得响应”,我想你暗示阻止它处理请求 - 响应进程中的线程,但不是主线程。
如果我确实了解这个问题吧,这里是我建议使用Qt来做到这一点:
#include <functional>
#include <QObject> // need to add "QT += core" in .pro
#include <QTcpSocket> // QT += network
#include <QtConcurrent> // QT += concurrent
#include <QFuture>
#include <QFutureWatcher>
class CommandSender : public QObject
{
public:
// Sends a command via connection and blocks
// until the response arrives or timeout occurs
// then passes the response to a handler
// when the handler is done - unblocks
void SendCommand(
QTcpSocket* connection,
const Command& command,
void(*responseHandler)(Response&&))
{
const int timeout = 1000; // milliseconds, set it to -1 if you want no timeouts
// Sending a command (blocking)
connection.write(command.ToByteArray()); // Look QByteArray for more details
if (connection.waitForBytesWritten(timeout) {
qDebug() << connection.errorString() << endl;
emit error(connection);
return;
}
// Waiting for a response (blocking)
QDataStream in{ connection, QIODevice::ReadOnly };
QString message;
do {
if (!connection.waitForReadyRead(timeout)) {
qDebug() << connection.errorString() << endl;
emit error(connection);
return;
}
in.startTransaction();
in >> message;
} while (!in.commitTransaction());
responseHandler(Response{ message }); // Translate message to a response and handle it
}
// Non-blocking version of SendCommand
void SendCommandAsync(
QTcpSocket* connection,
const Command& command,
void(*responseHandler) (Response&&))
{
QFutureWatcher<void>* watcher = new QFutureWatcher<void>{ this };
connect(watcher, &QFutureWatcher<void>::finished, [connection, watcher]()
{
emit done(connection);
watcher->deleteLater();
});
// Does not block,
// emits "done" when finished
QFuture<void> future
= QtConcurrent::run(this, &CommandSender::SendCommand, connection, command, responseHandler);
watcher->setFuture(future);
}
signals:
void done(QTcpSocket* connection);
void error(QTcpSocket* connection);
}
现在你可以使用从线程池取出一个单独的线程发送命令到插座:下引擎盖QtConcurrent::run()
使用由Qt为您提供的QThreadPool
的全局实例。该线程阻塞,直到它得到一个响应,然后用responseHandler
来处理它。同时,管理所有命令和套接字的主线程将保持畅通。只需抓住done()
信号即可知道响应已成功接收和处理。
有一点需要注意:异步版本只有在线程池中有空闲线程时才发送请求,否则就等待它。当然,这是任何线程池的行为(这正是这种模式的要点),但不要忘记这一点。
另外我写的没有Qt的代码很方便,所以可能会包含一些错误。
编辑:事实证明,这不是线程安全的,因为套接字在Qt中不可重入。
你可以做的是将一个互斥量与一个套接字关联,并在每次执行其功能时将其锁定。这可以很容易地创建QTcpSocket类的包装。请纠正我,如果我错了。
请问为什么你要使用多线程的解决方案? Qt的事件系统能够通过一个线程处理数百个Tcp连接,而不会出现麻烦,或者你的“套接字数据处理程序” - 逻辑阻塞主线程? – Spiek
感谢评论,我刚刚编辑帖子。它需要阻塞直到得到响应。 – Vido
有没有你不使用信号和插槽机制的原因?你可以使用QTcpSocket的readyRead-Signal并将它连接到一个插槽。 – Spiek