雖然,答案已經被接受了,我想和大家分享我的)
我從你的問題明白了什麼:有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