When it comes to "size" there are two dimensions and two measurements.
1) "kilo" might mean 1000 (10**3) or 1024 (2**10)
2) "b" might mean "byte" or "bit."
Traditionally, in computer engineering, when talking about data amounts, "kilo" has always meant 1024. However, when it comes to storage (hard disks,) and throughput (networks,) the marketing people have started using 1000, because that allows them to claim a higher number of kilo-somethings. Thus, it's important to know which particular convention is used when you look at the number. Some computer people have taken to calling the 1024-based kilos "kibis" -- "1 kibibyte" would be 1024 bytes. It's not a very widespread phenomenon, but if you see it, you will know what that means.
"Bits" versus "bytes" also matters in throughput. An internet service provider will almost always specify "b" as in "bits" -- and it takes between 8 and 10 bits to send a "byte" (depending on the overhead of the communication medium.) Actually it can take even more, if you're talking on very lossy channels. Engineers who care to make the distinction, usually use small-b for bits, and big-B for bytes. So, 1 kB is 8 kb, and might take as much as 10 kb of bandwidth. But a lot of people forget, or don't know, or otherwise get it wrong, so again, it's important to make sure you understand where the number came from, so you know how to interpret it.
Finally, when it comes to sending and receiving data, any protocol will generally use a little bit of framing around the actual data. Typically, you'll see a "type" field, followed by a "length" field, followed by the actual data. Each of those "type" and "length" fields may have different encodings -- single bytes, 4-byte integers, 8-byte integers, variable-length integers, text-mode encoding all exist. And, for the integers, little-endian, and big-endian encodings both exist.
Some encodings use a "terminating value" instead of a "prefix length" -- e g, they send data - data - data - data - terminator. The other end then should stop expecting more data when seeing the terminator. However, if the data could contain the same byte values as the terminator (often, a single 0-byte is a terminator) then this creates an ambiguity, which breaks communication, and causes bugs (and even zero-day security vulnerabilities.) I strongly recommend against using a terminator.
Make sure that you validate the data you receive. If a type value comes in, and it's not one you recognize, emit an error and close the connection. If a length value comes in, and it's not reasonable for the type value (too short, or too long,) or if it's bigger than you can easily allocate (some maximum limit you impose for safety,) then emit an error and close the connection. If you spend more than a generous amount of time waiting for data without receiving it, or if the throughput of the data is lower than you'd reasonably expect, time out, emit an error, and close the connection. All of these are both so that you can find bugs in your own code, and so that you can avoid certain kinds of bad behavior / attacks by people on the internet. For example, a popular way of trolling a server is to open a connection, send a single byte, and then send nothing more. The other end will wait for a long time for the next byte, which will take up server resources. And, if there's a timeout between bytes, another attack is to open a connection, and send one byte every 9 seconds. This will avoid the timeout, yet tie up resources that aren't useful. (This is why a throughput gate, or a maximum-transaction-timeout, is useful.)
Finally, when you call recv(), you have to realize that you may receive anything between 1 and full-buffersize bytes. The machinery between the sender and the recipient will re-package the data being sent, so even if the sending side calls send(128), the receiving end may not see that as a single chunk of 128 bytes, but might instead get one chunk of 1 byte, one chunk of 126 bytes, and the final byte might be the first byte of some next chunk that's sent because the sending end sent more data afterwards. This is because TCP is a "stream" that doesn't recognize "packet boundaries," and thus you usually do best with the known-size type and size fields before variable-sized data.
Good luck with your project!