Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Send big string into socket

I'm new with C++ and came to this problem. I'm trying to send big string to a socket. I've seen the similar questions on stack but could not found the real answer. For example these:

Sending a long String over a Socket C++

Send a string with sockets in C++ (Winsock TCP/IP)

C++ sending string over socket

Most of them rely on fact that send would send the whole data in one call, or they would use char * instead of std::string.

Here is little code written in C:

int SendAll(SOCKET client_socket, const void *data, int data_size)
{
    const char *data_ptr = (const char*) data;
    int bytes_sent;

    while (data_size > 0)
    {
        bytes_sent = send(client_socket, data__ptr, data_size, 0);
        if (bytes_sent == SOCKET_ERROR)
            return -1;

        data_ptr += bytes_sent;
        data_size -= bytes_sent;
    }

    return 1;
}

and now imagine that instead of const void *data we have std::string data. The question is how can I move pointer into data like this data_ptr += bytes_sent; with std::string?

One way that I came out is to retrieve the row pointer of std::stirng save it in some const char * var then use that variable in the same way(var += bytes_sent). But as I'm new with C++ I don't know if it's the "C++ way" of doing this? Is this the best solution to this problem or is there better one? thanks

like image 443
user3503143 Avatar asked Jun 06 '19 11:06

user3503143


2 Answers

Yes, that is the best way.

You have to obtain a pointer to the data anyway, to use send, so just adjust the pointer as you see fit.

Something like:

int SendAll(SOCKET client_socket, const std::string& str)
{
    const char* data_ptr  = str.data();
    std::size_t data_size = str.size();

    int bytes_sent;

    while (data_size > 0)
    {
        bytes_sent = send(client_socket, data_ptr, data_size, 0);
        if (bytes_sent == SOCKET_ERROR)
            return -1;

        data_ptr += bytes_sent;
        data_size -= bytes_sent;
    }

    return 1;
}

This is perfectly fine and idiomatic.

If you want to keep both versions of the function, just forward the string's buffer to your existing overload:

int SendAll(SOCKET client_socket, const std::string& str)
{
    return SendAll(
        client_socket,
        reinterpret_cast<const void*>(str.data()),
        str.size()
    );
}
like image 169
Lightness Races in Orbit Avatar answered Oct 21 '22 16:10

Lightness Races in Orbit


ssize_t send(int sockfd, const void *buf, size_t len, int flags);

This is the signature of send. It requires a pointer to the buffer. Although a C++ API would probably prefer a pair of iterators, rather than a pointer and a size, this is not really possible here, seeing that the pointer to the actual buffer is required. So, there's nothing you can do about it, really. You can just use the string's data() member function to get a poninter to the start of the buffer, and work with that. This should be perfectly fine.

As suggested by Some programmer dude in the comments, you could add a simple overload that facilitates this:

int SendAll(SOCKET client_socket, std::string const& str) {
    return SendAll(client_socket, reinterpret_cast<const void*>(str.data()), str.size());
}
like image 42
Cássio Renan Avatar answered Oct 21 '22 17:10

Cássio Renan