Вы можете порождать клиента в его собственном потоке и вращать блокировку / ожидание (тайм-аут) для его возврата. Возможно использование объекта Future для получения возвращаемого значения, если Socket успешен.
Я верю, что настройка SO_TIMEOUT для Socket влияет только на вызовы чтения (..) из сокета, а не на запись.
Вы можете попробовать использовать SocketChannel (а не Stream) и порождать другой поток, который также имеет дескриптор этого канала. Другой поток может асинхронно закрыть этот канал после того, как определенный тайм-аут его заблокирован.