As a message length prefix in TCP / IP

I send messages over TCP / IP, I need a message length prefix in the char array, and then send it. How to do it?

You can also give an example of how to extract it at the other end. And if possible, please explain.

I use C ++ and Winsock.

EDIT:

string writeBuffer = "Hello";

unsigned __int32 length = htonl(writeBuffer.length());

It does not return the correct length, but 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 this so? I get 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;
}
+3
source share
3 answers

When sending a length field in a TCP stream, you need to solve two things:

  • what length should have a length (1 byte, 2 bytes, 4 bytes, variable length)
  • what's the point of using i

4 (.. big-endian). htonl ntohl (native) byte order (little-endian ) .

, :

size_t length = strlen(data);
uint32_t nlength = htonl(length);
send(sock, &nlength, 4, 0);
send(sock, data, length, 0);

, :

uint32_t length, nlength;
recv(sock, &nlength, 4, 0);
length = ntohl(nlength);
data = malloc(length+1);
recv(sock, data, length, 0);
data[length] = 0;

- : ; recvs , . .

. , recv , , , ,

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;
}
+6

( , ):

:

u_long converted = htonl( messageLength ); // convert from local byte order to network byte order
send( socket, (char*)&converted, sizeof( converted ), 0 );

:

u_long messageLength;
recv( socket, (char*)&messageLength, sizeof( messageLength ), 0 );
messageLength = ntohl( messageLength ); convert from network byte order to local byte order
+1

I'm not sure if this is what you are asking for, but I would send it as a string of fixed length (say 4 characters, the actual length is up to you). In other words, if the data length is 164, send the string "0164". This overcomes any problems with the byte order on the other end and is easy to read and debug.

To create such strings, you can use stringstream:

#include <sstream>
#include <iomanip>

std::string MakeLenStr( int n ) {
  std::ostringstream os;
  os << std::setw(4) << std::setfill('0') << n;
  return os.str();
}

Submit:

std::string s = MakeLenStr( len );
send( sock, s.c_str(), 4 );

To read it at the other end, something like:

char a[5] = {0};
recv( sock, a, 4 );
int n = atoi( a );
0
source

Source: https://habr.com/ru/post/1716176/


All Articles