Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable length Message over TCP Socket in C++

I was trying to send some length prefix data to the server, i have tried harder by using the code and solution posted by other people on stack overflow. Still looking how things are actually working using TCP.As i don't know so much(about network programming but i am aware about theoretical concepts). i am writing what i have tried so far.Based on that i have some questions.

As we are using Char Buffer[200] = "This is data" on client side to send(using send() function) string and char type data to server(receiving using recv()function). Till here its okay but what if i need to send some variable length message with their length information ? , How i can encode length info to the message ?

for example:  0C     54 68 69 73 20 69 73 20 64 61 74 61     07    46 72 6f 6d 20 6d 65
           (length)  T  h   i  s    i   s     d  a  t  a   (length) F  r  o  m     m  e


How can i interpret these two message seperately from tcp stream  at the sever side ?

i dont know how length information can be sent separetly ?. Or if someone can understand my test case(given below in edit) to verify length information of the string.

EDIT: It seems okay but i just need verify a bit about prefix length. I am sending 20 bytes("This is data From me") to server. My recevied length size is 4 bytes(i dont know whats inside, i need to verify does the 4 bytes of length i received contain 0000 0000 0000 0000 0000 00000 0001 0100). Thats it, so the way i thought to verify it by shifting length info by 2 bits right now it should look like ( 4 bytes of length i received contain 0000 0000 0000 0000 0000 00000 0000 0101) in this case i should get only 5 characters i.e "This ". Do you know how can i verify this at server side ?

Client Code

int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[200] = "This is data From me";

int  nBytes = 200, nLeft, idx;
nLeft = nBytes;
idx = 0;
uint32_t varSize = strlen (sendbuf);
bytesSent = send(ConnectSocket,(char*)&varSize, 4, 0);
assert (bytesSent == sizeof (uint32_t));
std::cout<<"length information is in:"<<bytesSent<<"bytes"<<std::endl;
// code to make sure  all data has been sent
  while (nLeft > 0)
{
    bytesSent = send(ConnectSocket, &sendbuf[idx], nLeft, 0);
    if (bytesSent == SOCKET_ERROR)
    {
      std::cerr<<"send() error: " << WSAGetLastError() <<std::endl;
      break;
    }
    nLeft -= bytesSent;
    idx += bytesSent;
}
bytesSent = send(ConnectSocket, sendbuf, strlen(sendbuf), 0);
 printf("Client: Bytes sent: %ld\n", bytesSent);

Server Code

     uint32_t  nlength;
int length_received = recv(m_socket,(char*)&nlength, 4, 0);
char *recvbuf = new char[nlength];
int byte_recived = recv(m_socket, recvbuf, nlength, 0);

Thanks

like image 247
User Avatar asked Mar 21 '23 16:03

User


1 Answers

If you need to send variable-length data, you need to send the length of that data before the data itself.

In you code snippet above, you appear to be doing the opposite:

while (nLeft > 0)
{
    bytesSent = send(ConnectSocket, &sendbuf[idx], nLeft, 0);
    // [...]
}
bytesSent = send(ConnectSocket, sendbuf, strlen(sendbuf), 0);

Here you send the string first, and then the length. How is the client going to be able to interpret that? By the time the get the length, they have already pulled the string off the socket.

Instead, send the length first, and make sure you're explicit about the size of the size field:

const uint32_t varSize = strlen (sendbuf);
bytesSent = send(ConnectSocket, &varSize, sizeof (varSize), 0);
assert (bytesSent == sizeof (uint32_t));
while (nLeft > 0)
{
    bytesSent = send(ConnectSocket, &sendbuf[idx], nLeft, 0);
    // [...]
}

You might also consider not sending variable-length data at all. Fixed-width binary protocols are easier to parse on the receiving side in general. You could always send string data in a fixed-width field (say, 20 chars) and pad it out with spaces or \0's. This does waste some space on the wire, at least in theory. If you are smart about the sizes of the fixed-width fields and what you send in them, you can be economical with this space in many cases.

like image 155
John Dibling Avatar answered Apr 06 '23 21:04

John Dibling