We can get very simple reliable request-reply with some changes to the client. We call this the Lazy Pirate pattern. Rather than doing a blocking receive, we: Poll the REQ socket and receive from it only when it's sure a reply has arrived. Resend a request, if no reply has arrived within a timeout period. Abandon the transaction if there is still no reply after several requests.
Implement the Client-Side Reliability (Lazy Pirate Pattern) example.