В принципе у меня каждый ответ на команду имеет ID, так что можно в отдельном "как бы потоке" читать блокирующим образом и если у считанного есть префикс ID - смотреть, зарегистрирован ли для данного префикса обработчик и вызывать его. А если нет обработчика или нет ID, как в случае с greetings header, - ничего не делать. Тогда можно из основного потока выдать N запросов серверу подряд, поставив на каждый из них обработчик, а читающий "поток" каждый такой обработчик запустит, если и когда придёт ответ от сервера. Правда, если не придёт, то ... да, можно запустить ещё одну нить, которая будет просматривать очередь ещё не обработанных сервером запросов и если в этой очереди есть слишком долго не отвеченные - вызывать обработчик.