简体   繁体   中英

Read all data during single recv() method from a socket

I am trying to continuously read the data using socket programming. I use recv() which receives data on a socket. I store it in a buffer. recv() returns the number of bytes read. Following is the snippet:

while (true) {
        try {
            char buff[2048];
            int bytes = recv(sockfd, buff, 2048, 0);
            buff[bytes] = '\0';
            cout << strlen(buff) << endl;
            cout << bytes << endl;
            cout << "-------" << endl;
        } catch (const char *e) {
        }
    }

Following is the output of the code:

1
1204
-------
1
1390
-------
1
25
-------
1
1204
-------

The number of bytes received are correct through recv() method but I am not able to read the exact number of data. How can I read all the data captured during single recv() method?

You need to pass proper flag to recv as in documentation. Basing on: https://man7.org/linux/man-pages/man2/recv.2.html there is flag MSG_WAITALL (since Linux 2.2) that do what you want.

The call would look like:

int bytes = recv(sockfd, buff, 2048, MSG_WAITALL);

And checking length of received bytes by strlen is bad unless you are sure you receive only text.

You can create a std::string_view pointing at the data read.

while (true) {
    char buff[2048];
    int bytes = recv(sockfd, buff, 2048, 0);
    if (bytes >= 0) {
        std::string_view read { buff, bytes };
        std::cout << read << std::endl;
        std::cout << "-------" << std::endl;
    } // else?
}

The function strlen will treat the contents of buff as a null-terminated string and return the length of that string.

In the line

buff[bytes] = '\0';

you wrote a null terminating character at the end of the data. That way, you have ensured that the data is null-terminated.

However, it is possible that the bytes that were read by recv contain a byte with the value 0 . The function strlen will be unable to distinguish between such a byte and the actual terminating null character. It will simply return the index of the position of the first byte with the value 0 .

That is why the expression strlen(buff) does not correspond to the actual length of the data.

For this reason, you should not be using the function strlen on binary data. That function is only intended for text data, which cannot contain a character with the value 0 , except to mark the end of the string.

Instead of using strlen to determine the length of the data, you should only be using the value returned by recv (which you have stored in the variable bytes ). As long as you remember this value, you will always know the length, so there is no need to mark the end of the data with a terminating null character.

Provided that recv returned a positive value (negative would indicate failure), you will find all of the data in the array buff , and the return value of recv will specify the length of the data. If you want to, for example, print all of the data that you have received in your function call to recv , you could write the following immediately after the recv function call:

for ( int i = 0; i < bytes; i++ )
    cout << hex << setw(2) << setfill( '0' ) << static_cast<int>(buff[i]) << ' ';

Note that you must add #include <iomanip> at the start of your program for this line to work.

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