1

I'm very new to C++, but I'm trying to learn some basics of TCP socket coding. Anyway, I've been able to send and receive messages, but I want to prefix my packets with the length of the packet (like I did in C# apps I made in the past) so when my window gets the FD_READ command, I have the following code to read just the first two bytes of the packet to use as a short int.

char lengthBuffer[2];

int rec = recv(sck, lengthBuffer, sizeof(lengthBuffer), 0);

short unsigned int toRec = lengthBuffer[1] << 8 | lengthBuffer[0];

What's confusing me is that after a packet comes in the 'rec' variable, which says how many bytes were read is one, not two, and if I make the lengthBuffer three chars instead of two, it reads three bytes, but if it's four, it also reads three (only odd numbers). I can't tell if I'm making some really stupid mistake here, or fundamentally misunderstanding some part of the language or the API. I'm aware that recv doesn't guarantee any number of bytes will be read, but if it's just two, it shouldn't take multiple reads.

user1869878
  • 83
  • 1
  • 6
  • do you want to find amount of bytes being sent and recieved or just available amount of bytes to be sent? Maybe Help or not based on question - http://stackoverflow.com/questions/12984816/get-the-number-of-bytes-available-in-socket-by-recv-with-msg-peek-in-c – Irrational Person Dec 17 '14 at 22:01
  • just might be a **duplicate** based on how many other similar questions there are. – Irrational Person Dec 17 '14 at 22:04
  • The "correct number of bytes" for a TCP socket in blocking mode is one or more. See the *man* page. Your expectations are unfounded. – user207421 Dec 17 '14 at 22:43

3 Answers3

5

Because you cannot assume how much data will be available, you'll need to continuously read from the socket until you have the amount you want. Something like this should work:

ssize_t rec = 0;
do {
    int result = recv(sck, &lengthBuffer[rec], sizeof(lengthBuffer) - rec, 0);
    if (result == -1) {
        // Handle error ...
        break;
    }
    else if (result == 0) {
        // Handle disconnect ...
        break;
    }
    else {
        rec += result;
    }
}
while (rec < sizeof(lengthBuffer));
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Julian
  • 1,688
  • 1
  • 12
  • 19
1

Streamed sockets:

The sockets are generally used in a streamed way: you'll receive all the data sent, but not necessarily all at once. You may as well receive pieces of data.

Your approach of sending the length is hence valid: once you've received the length, you cann then load a buffer, if needed accross successive reads, until you got everything that you expected. So you have to loop on receives, and define a strategy on how to ahandle extra bytes received.

Datagramme (packet oriented) sockets:

If your application is really packet oriented, you may consider to create a datagramme socket, by requesting linux or windows socket(), the SOCK_DGRAM, or better SOCK_SEQPACKET socket type.

Risk with your binary size data:

Be aware that the way you send and receive your size data appers to be assymetric. You have hence a major risk if the sending and receiving between machine with CPU/architectures that do not use the same endian-ness. You can find here some hints on how to ame your code platform/endian-independent.

Christophe
  • 68,716
  • 7
  • 72
  • 138
  • Cant you just use ntohs and htons instead of the suggested codes given on the link you provided? – kuchi May 27 '16 at 17:56
0

TCP socket is a stream based, not packet (I assume you use TCP, as to send length of packet in data does not make any sense in UDP). Amount of bytes you receive at once does not have to much amount was sent. For example you may send 10 bytes, but receiver may receive 1 + 2 + 1 + 7 or whatever combination. Your code has to handle that, be able to receive data partially and react when you get enough data (that's why you send data packet length for example).

Slava
  • 43,454
  • 1
  • 47
  • 90
  • `length in data does not make any sense in UDP` what? – Julian Dec 17 '14 at 22:13
  • Right, I get that, which is why I'm using this approach. Sorry if I was unclear (I used packet to refer to a complete segment of data, even if that's not really correct terminology for TCP). What I'm confused by is why recv will only read odd numbers of bytes and never the whole size of the buffer. The length of the data I'm sending is only 15 bytes (the first two being the length) and my buffer is two bytes, so it shouldn't take two calls to fill that buffer. I can make this work if I make my buffer larger and read the first two bytes from the first receive, but I don't understand why. – user1869878 Dec 17 '14 at 22:15
  • @AtlasC1 I mean to send length of packet inside UDP packet does not make any sense – Slava Dec 17 '14 at 22:17
  • 2
    @user1869878 you cannot assume how data will be splitted when you get it, no matter what buffer size you use. Your code has to handle that. – Slava Dec 17 '14 at 22:19