It depends. Forget the involved technologies for a while and focus on your specific comm needs. Hope you don't mind if I explore a few related points as well.
- Point-to-point (p2p) flow: We know this one - Duplex, as you mentioned.
- p2p mode: Half- or Full-duplex? Will data be exchanged simultaneously, or it is always a message-response mechanism?
- State: You may have code that will wait for a response, even if the major part of your exchange is asynchronous. Is the exchange absolutely async? sync? mixed? This point is tightly related to the previous one.
- Transmission: Data bursts, or constant streams?
- Bandwidth: How many bytes/sec do you expect to traffic around? Is it a considerable percent of your target network (wireless? mobile? hi-speed?)
- Reliable/unreliable content: Does the loss of a data package tosses your client state in disarray? (This isn't a bad thing per se, just a spec.)
If your code needs any kind of synchronous content, then you may need a reply flow control on you code, and a Messaging structure of some sort where Messages have an ID and may have a Original Message ID to which they are a reply. This will help you control content even on async protocols. In this case, an easily maintanable protocol like JSON may be better, as @JustLogin mentioned.
Full-Duplex mean you be staging more data on your network/interpreter layer, and it probably will have to handle asynchronous communications.
If performance is a concern, and depending on your specifics, then proposals like the one made by @Viacheslav can be attractive. A custom protocol can be heavily optimized, at the cost of maintanability and portability (several languages have their own JSON interpreter, while custom interpreters may need to be implemented or encapsuled, adding layers to the process and thus lowering performance, or requiring code conversion.)
If you couldn't care less if a packet or two are lost, then UDP may be a viable solution. Less control than TCP means a lighter protocol, but you're never sure that the data reached the other side unless you implement your own control.
TL;DR version: I would stick to standard low-level protocols like JSON, even if they add some overhead.