It's a very bad to implement all protocol stuff manually, you will spent a many time on the
very simple, but annoying job, and you will create s new bugs, a lot of ugly code and so on ...
In the real distributed systems is many kind of intercommunication exist, I mean that you need some protocol for system-wide bus, some other protocol for services of the group A and some other for the other groups. Usually you will has a tons of different protocols and it will be a problem to create new one or update/modify existing.
I found two ways to fix this headache and one of this way is widely used in the systems of such kind, it's IDL. It may be ORB/CORBA like interface description language and usually is it.
Mainly, you need to pass some typed message and get some typed response to this message, and this problem is finely solved in CORBA-like IDLs, in contrast if you are working in the complex distributed system you need to have many indirect message passing system that will impact to your protocol.
In the system of such kind you also need to determine the message sender, his priority, and his level of the access or, more widely, what the access rights has this message. While you are going deeper you will understand that for some complex systems (like distributed system for transport queue management) that should works with determined time range you will need something like QoS (yep, I mean here quality of service). There impacts are going to your protocol.
Now, imagine that you have a CORBA-like IDL and you need extended option described above ...
You will describe some proto on IDL, and you will implement QoS, protocol for access inheritance manually ... In this case it's a good point to think where is headache located ?
The other way - it's a runtime solution for passing arguments via messages it will has the same disadvantages, but will be simply in implementation.
Well, the question is open - where is a mixture for headache with distributed message passing ?