There are two basic ways to deal with this, both of which can use a queue, and probably even should, but can be implemented in various ways. Note that there are many implementations out there, and you should probably use one unless you have a particular reason not to (e.g. you're just researching the subject for now). Those two ways are:
That last bit was a joke. The difference between the two is (beyond implementation details) whether your caller tries to do something else in the meantime, nothing else.
If you use a blocking technique, then your call doesn't return until it either gets a result, or it concludes (either from being told, or just guessing) that there will never be a result.
If you use a non-blocking technique, then your function returns as soon as it's queued the request, and you either have to check for a result every once in a while (which, it's worth noting, might itself be done by checking another queue!), or establish a handler that'll be called when a response arrives.