Are both sides "waiting for the opponent"? That sounds more like a deadlock condition, each side waiting for the other to release a needed resource.
Sure, log everything at the lowest possible level. Then you know will know for sure what got sent and when.
Another common variation, if you're using blocking I/O, is for a process to block because it's output buffer
is full, while the receiver is also blocked either for the same reason or because it is waiting for a response
that it thinks ought to be in the pipeline somewhere. You should not depend on the buffering
capacity of the TCP stream. You should never wait synchronously for a response.
My games have a
(a) a reader thread that reads messages from the TCP stream and queues them for the game
thread to process.
(b) a game thread that processes messages from the reader thread (and also other sources of input
such as the mouse and keyboard). It queues outgoing messages for a writer thread to deliver, but
never waits for them to be sent.
(c) a writer thread that sends messages that were queued for it to send.