How do I prefix the length of message in TCP/IP
c++, tcp, winsock
Solution
When sending a length field on a TCP stream, you need to decide two things:
- what length should the length have (1 byte, 2 bytes, 4 bytes, variable length)
- what endianness should I use
I recommend to use 4 bytes length, and network byte order (i.e. big-endian). For network byte order, the macros htonl and ntohl will convert between host (native) byte order (little-endian, in your case), and network byte order.
To send data, the fragment should look like this:
size_t length = strlen(data);
uint32_t nlength = htonl(length);
send(sock, &nlength, 4, 0);
send(sock, data, length, 0);
On the receiving side, you extract first the length, then the data:
uint32_t length, nlength;
recv(sock, &nlength, 4, 0);
length = ntohl(nlength);
data = malloc(length+1);
recv(sock, data, length, 0);
data[length] = 0;
What this code is missing is error handling: each of the send and receive calls may fail; the recvs may receive less data than expected. But this should give you an idea.
Edit: To deal with the case that the recv returns too few data, run it in a loop, keeping a count of what you have read so far, e.g.
int length_bytes = 0;
while(length_bytes < 4){
int read = recv(sock, ((char*)&nLength)+length_bytes, 4-length_bytes, 0);
if (read == -1) some_error_occurred_check_errno();
length_bytes += read;
}
Problem
I'm sending messages over TCP/IP, I need to prefix message length in a char array and then send it. How do I do it? Also can you please provide an example of how to extract it at the another end. And if possible, please explain. I'm using C++ and Winsock. EDIT: ``` string writeBuffer = "Hello"; unsigned __int32 length = htonl(writeBuffer.length()); ``` It's not returning the correct length rather a very large number. For the receiving part, if I use ntohl(), then I also get a large number instead of the correct length? Why is that so? I'm receiving like this ``` bool Server::Receive(unsigned int socketIndex) { // Read data from the socket if (receivingLength) { bytesReceived = recv(socketArray[socketIndex - WSA_WAIT_EVENT_0], ((char*)&messageLength) + bytesReceived, MESSAGE_LENGTH_SIZE - bytesReceived, 0); if (bytesReceived == SOCKET_ERROR) { return false; } if (bytesReceived == MESSAGE_LENGTH_SIZE) { // If uncomment the following line, // I won't get the correct length, but a large number //messageLength = ntohl(messageLength); receivingLength = false; bytesReceived = 0; bytesLeft = messageLength; } } else { if (bytesLeft > BUFFER_SIZE) { return false; } bytesReceived = recv(socketArray[socketIndex - WSA_WAIT_EVENT_0], &receiveBuffer[bytesReceived], bytesLeft, 0); if (bytesReceived == SOCKET_ERROR) { return false; } if (bytesReceived == messageLength) { // we have received full message messageReceived = true; receiveBuffer[bytesReceived] = '\0'; // wait for next message receivingLength = true; } bytesLeft -= bytesReceived; } return true; } ```