7

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

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
user3503143
  • 381
  • 3
  • 10
  • Why not call the function like `SendAll(the_socket, the_string.c_str(), the_string.size())`? – Some programmer dude Jun 06 '19 at 11:06
  • thats another idea of solution, thats why I said what is the best way to do this? – user3503143 Jun 06 '19 at 11:08
  • 1
    In my personal opinion, that's the simplest and most straight-forward way to handle it. You could create an overload that takes the string as argument, and then calls the shown `SendAll`. Like `int SendAll(SOCKET client_socket, std::string const& str) { return SendAll(client_socket, str.c_str(), str.size()); }` – Some programmer dude Jun 06 '19 at 11:11
  • So retrieving the row pointer from `std::string` and manipulating it is ok with c++? – user3503143 Jun 06 '19 at 11:12
  • With that said, asking "what is the best way to do *anything*" isn't really a good question here, as it's very subjective and opinion based. Please take some time to refresh [the help pages](http://stackoverflow.com/help), especially the sections named ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic) and ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask). – Some programmer dude Jun 06 '19 at 11:13
  • In the "best way..." I meant the way it should be done in c++ – user3503143 Jun 06 '19 at 11:14
  • You can post answer and I'll submit as answered – user3503143 Jun 06 '19 at 11:23

2 Answers2

6

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()
    );
}
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
3
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());
}
Not a real meerkat
  • 5,604
  • 1
  • 24
  • 55