Du musst erstmal etwas grundsätzliches verstehen:
TCP ist einfach nur ein "Stream of Bytes", das heißt eine Kette von einzelnen Bytes. Es gibt auch keine
TCP-Pakete, sondern nur Segmente. Diese Segmente sind einfach Teile des Datenstroms. Das ist nichts, was von höheren Protokollen oder Ebenen kontrolliert wird. Das macht die Hardware, mit ihrer Firmware und ggf. noch dem Treiber, eventuell konfiguriert durch das
OS unter sich ab.
Alles darüber sind höchsten "leaky abstractions". Wenn du beispielsweise in deiner Komponente definierst, dass du feste Line-Endings benutzt, dann sammelt die einfach was ankommt ein bis dieses Zeichen auftaucht und stellt es dir bereit. Gleichzeitig ist wenn du etwas mit festem Line-Ending sendest eben nicht garantiert, dass das alles in einem Segment rausgeht oder ankommt.
Wenn du ohne Line-Ending arbeitest, dann musst du entweder ein Protokoll mit fester "Message"-Größe entwerfern und dann immer so viele Bytes lesen wie du brauchst, ein Protokoll entwerfen bei dem (am besten am Anfang) die Information mitkommt wie viele Bytes noch gelesen werden müssen, oder eben einen komplexen Parser bauen, wenn beides nicht möglich ist.
UDP hingegen arbeitet mit einzelnen Datagrammen. Dafür hat man keinerlei Garantie in welcher Reihenfolge diese ankommen, oder ob sie überhaupt ankommen.
Falls es dir auf einzelne Datagramme ankommt, dann kannst du UDP nutzen und musst ggf. sowas wie Reihenfolge-Management oder gar Re-Transmit selbst in deinem Protokoll implementieren.
Oder: Du nutzt nicht
TCP "direkt", sondern nutzt ein ganz anderes Protokoll, was dir mehr Arbeit abnimmt. Ich nutze gerne *MQ-Protokolle wie MQTT oder Zero-MQ.
Ein anderer Tipp ist Server oder Client auch mal in einer anderen Programmiersprache eventuell gar durch eine andere Person implementieren zu lassen. Du glaubst nicht, was man da für Fehler findet...