Sending and receiving std::string over socket
Solution 1
No it can't. c_str() returns a const char*
. This means you cannot overwrite the contents of the pointer.
If you want to receive the data, you must create a buffer, e.g. with a std::vector
and then use that to create a std::string
.
// create the buffer with space for the data
const unsigned int MAX_BUF_LENGTH = 4096;
std::vector<char> buffer(MAX_BUF_LENGTH);
std::string rcv;
int bytesReceived = 0;
do {
bytesReceived = recv(*csock, &buffer[0], buffer.size(), 0);
// append string from buffer.
if ( bytesReceived == -1 ) {
// error
} else {
rcv.append( buffer.cbegin(), buffer.cend() );
}
} while ( bytesReceived == MAX_BUF_LENGTH );
// At this point we have the available data (which may not be a complete
// application level message).
The above code will receive 4096 bytes at a time. If there is more than 4K sent, it will keep looping and append the data to recv
until there is no more data.
Also note the use of &buffer[0]
instead of buffer.data()
. Taking the address of the first element is the way to access the non-const pointer and avoid undefined behavior.
Solution 2
The best way is to send the length of the string data first in a fixed format (e.g. a uint32_t
in network byte order). Then the receiver can read this first and allocate a buffer of the appropriate size before receiving the serialized message that is send afterwards.
sd
and csd
are assumed to be already present socket descriptors.
Sender.cpp
std::string dataToSend = "Hello World! This is a string of any length ...";
uint32_t dataLength = htonl(dataToSend.size()); // Ensure network byte order
// when sending the data length
send(sd,&dataLength ,sizeof(uint32_t) ,MSG_CONFIRM); // Send the data length
send(sd,dataToSend.c_str(),dataToSend.size(),MSG_CONFIRM); // Send the string
// data
Receiver.cpp
uint32_t dataLength;
recv(csd,&rcvDataLength,sizeof(uint32_t),0); // Receive the message length
dataLength = ntohl(dataLength ); // Ensure host system byte order
std::vector<uint8_t> rcvBuf; // Allocate a receive buffer
rcvBuf.resize(dataLength,0x00); // with the necessary size
recv(csd,&(rcvBuf[0]),dataLength,0); // Receive the string data
std::string receivedString; // assign buffered data to a
receivedString.assign(&(rcvBuf[0]),rcvBuf.size()); // string
Advantage is. you don't have to mess around with multiple buffered reads and copying to the received string. Additionally you'll know at the receiver side when the sent data is finally complete.
Disadvantage is, you're introducing kind of a 'protocol' when sending the length first.
Solution 3
No, std::string::c_str()
returns const char*
which is means it's read only. You could allocate a local buffer and create string object from local buffer after recv
returns successfully.
You need to tell recv
function to read a specific length of data, for example you want to read 512 bytes each time:
#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];
recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);
Catty
Updated on April 12, 2020Comments
-
Catty about 4 years
I have seen similar question on SO but non answers my question. Here I am trying to send and recv string:
I am sending std::string :
if( (bytecount=send(hsock, input_string.c_str(), input_string.length(),0))== -1)
Can it be correctly received by this?
if ((bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)) == -1)
I am getting error:
error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]` on recv line!
-
Catty over 10 yearsthanks, what is
length
instd::vector<char> buffer(length)
as I dont know what exactly the length of receiving data is? -
Catty over 10 yearsthanks, but what could be the size of local buffer? do we need to give it? because I dont know what would be the size of receiving value!
-
Steve over 10 yearsYou must decide the maximum amount of data you want to receive and define that as length. There is no way for you to know the amount of data that you will actually receive. If you receive less than your max buffer size you have the whole message, otherwise you need to call receive again as there is more data on the line.
-
Catty over 10 yearsI am dealing with big data comming from web pages. I suspect what should I use it! any other way?
-
Catty over 10 yearsI want solution which does not limit for buffer limited buffer size!
-
Catty over 10 yearsI want solution which does not limit for buffer limited buffer size!
-
Steve over 10 years@Catty to receive more data, you must loop and call
recv
again. Updated answer. -
David Schwartz over 10 years@Catty You need to design and implement a protocol (or use an existing protocol). Otherwise, how will the receiver know how many bytes to receive?
-
Catty over 10 yearsthanks a lot. I think this will solve my issue. Let me check for my application!
-
Catty over 10 years@DavidSchwartz: Yes, I was trying to implement protocol for my purpose. But I think Steve answer will dill with any size of data!
-
billz over 10 years@Catty, Steve's answer sets length 4096, it doesn't deal with any size.
-
Catty over 10 years@billz: But i believe it will work for any possible size, if I am not wrong!
-
Catty over 10 yearsshould it be
bytesReceived = recv(*csock, buffer.data(), buffer.length() -1 , 0));
? -
David Schwartz over 10 years// At this point we have all the data. - What does "all the data" mean exactly? (It's too easy for someone to erroneously think you mean an entire application-level message, which of course would be totally incorrect.)
-
David Schwartz over 10 years@Catty It will get you some data, but then you have to implement the actual protocol to decide whether that data constitutes an entire "message" or not. You can't avoid implementing a protocol.
-
alk over 10 yearsFor less then
MAX_BUF_LENGTH
sent your reader will block until the other end closes the connection. -
jww over 6 years+1 for using
&rcvBuf[0]
.