TCP implementations typically provide applications with only a streaming interface without access to individual packages. (In addition, some routers / firewalls may want to repackage the data in TCP streams, which means that they do not necessarily arrive in the same blocks as the sent ones.) Thus, we really need to use the packing protocol over TCP (or really over any pair of threads).
A simple protocol would be one line for each request / response, but this will only work with small data sizes (or you need to somehow avoid the inline new lines).
If you want it to be more structured, you could use something based on XML (e.g. XMPP): each request / response would be a complete XML element (including subelements, if necessary).
In addition, if you want to use a request-response scheme, you need to either say that the answers must come in the same order as requests for requests (which prohibits or at least complicates the parallel processing on the server side for several requests for same connection), or you have to determine the request numbers, and the answers then somehow include the number of the request to which they relate.
As an example, HTTP uses the first approach (from 1.1 before there was only one request / response pair for each connection), while the X protocol uses the second.
For HTTP, implementations already exist (both on the client side and on the server side), and it can be made completely open (depending on the data being sent).
Alternatively, we could build our protocol directly on a packet protocol such as UDP. But this has the usual UDP reliability problems, and we also need to use message numbers (to correlate the responses to the requests) or those that could mean that we must re-implement half of TCP again.
So sorry, no real answer other than using HTTP.