简体   繁体   中英

Error on receiving from socket

I need to receive messages from a server and I can do that so far but I still have a problem that I don't know what it is. The text defines that the message is follows format:

  • as header, 2 bytes for the size of the rest of the message (payload + checksum);
  • as trailer, 1 byte for checksum (the checksum is calculated including the 2 bytes of the size )
  • , and the rest of bytes are for the payload itself (in the middle of the message)

I was trying to receive that message and so I used a receive function that it's below

/**
    Receive data from the connected host
*/
    string client::receive(int size){
    //string buffer;
    string reply;
    std::vector<char> buffer(size, 0);
    //strcpy(buffer, "\0");
   // memset(&buffer[0], 0, sizeof(buffer));
    int result = recv(sock, buffer.data(), buffer.size(), 0);

    if( result < 0){
        puts("recv failed");
    }
    cout << "read bytes: " << result << endl;
    cout << "buffer: " << buffer.data() << endl;
    //reply = stringToBit(buffer);
    reply = buffer.data();
    cout << "reply: " << reply << endl;

    return reply;
    }

but the problem is, when I put the receive in a while to receive all messages, things start to get odd. At first, I realised that I only needed to clean the buffer but things stay strange because, for the messages, the information I receive are:

1rst Message: NULL - Number of bytes received: 2

2nd Message: User accepted - Number of bytes received: 14

3rd Message: 5 - Number of bytes received: 1

4th Message: NULL - Number of bytes received: 2

5th Message: unprintable_char 501&xt,md-ldt='t <1t?1-t$;=: - Number of bytes received: 30

6th Message: NULL - Number of bytes received: 1

.

.

.

The 5th message always change but the rest (messages and number of bytes) are always the same. When looking at messages 1 from 3, I thought that maybe 3 was the header with the size, 2 was the message and 3 the checksum. But, receiving all those NULL instead of any usefull information, makes me thing otherwise.

Does someone has some idea of what might be happening? I have zero control to the server, I can only believe that the server sends those messages as stated.

The server sends you the size of the message. You have to use this to your advantage. Also, the way you function is defined makes it difficult to report errors. You should consider something like this:

// receives a fixed number of bytes. returns zero or a negative number on error
int client::receiveBytes(size_t n, void* buffer)
{
     char* p = reinterpret_cast<char*>(buffer);
     while (n)
     {
         int got = recv(sock, p, n, 0);
         if (got <= 0)
             return got;
         n -= got;
         p += got;
     }
     return 1;
}

/**
Receive data from the connected host
*/
int client::receive(std::string& reply) 
{
    reply.clear();
    uint16_t replyLength = 0;    // or the appropriate 16-bit type if your compiler doesn't provide <cstdint>

    int result = receiveBytes(2, &replyLength);
    if (result <= 0)
        return result;

    if (replyLength == 0)  // <-- you could add more length validation here 
       return -1;          // <-- or whatever error code you wish...

    reply.resize(replyLength);
    result = receiveBytes(replyLength, &reply[0]);

    if (result <= 0)
        return result;

    // verify the checksum.  failure indicates we have lost sync...

    // I'm assuming here that the checksum is computed using plain char's,
    const char* p = reinterpret_cast<const char*>(&replyLength);
    char chksum = *(p++) + *p;

    for (size_t i = 0; i < replyLength - 1; ++i)
        chksum += reply[i];

    if (chksum != reply[replyLength - 1])
    {
         // there is not much that can be done to recover sync with this protocol
         // the best option the caller has is to close the connection and start anew.
         reply.clear();
         return -1;   // or whatever error code you wish...
    }
    reply.resize(replyLength - 1);
    return reply.size();
}

I created another receive function just for the 16 bits integers and (for some reason I don't know), I realised that the bytes were exchanged. For example:

I received the number 3840, that the binary representation is: 0000111100000000

But I was supposed to receive 15, that the binary representation is: 0000000000001111

So, in addition to the receive, I add some byte exchange idea

 int client::receiveSize(){
    int16_t size;
    int result = recv(sock, &size, sizeof(size), 0);

    int hibyte = (size & 0xff00) >> 8;
    int lobyte = (size & 0xff);
    size = lobyte << 8 | hibyte;
    cout << "received: " << size << " and " << result<< endl;
    return size;
}

I realised (way! I learned something), that I should put exactly the data type that I'll be receiving on the recv. Otherwise, I can get information that doesn't make sense.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM