C++ 通过套接字发送和接收 std::string
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18670807/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Sending and receiving std::string over socket
提问by Catty
I have seen similar question on SO but non answers my question. Here I am trying to send and recv string:
我在 SO 上看到过类似的问题,但没有回答我的问题。在这里,我试图发送和接收字符串:
I am sending std::string :
我正在发送 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!
错误:recv 行上从“const void*”到“void*”[-fpermissive]` 的无效转换!
回答by Steve
No it can't. c_str()returns a const char*
. This means you cannot overwrite the contents of the pointer.
不,不能。 c_str()返回一个const char*
. 这意味着您不能覆盖指针的内容。
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
.
如果您想接收数据,您必须创建一个缓冲区,例如使用 astd::vector
然后使用它来创建一个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.
上面的代码一次将接收 4096 个字节。如果发送的数据超过 4K,它将继续循环并将数据附加到,recv
直到没有更多数据。
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.
还要注意使用&buffer[0]
代替buffer.data()
。获取第一个元素的地址是访问非常量指针并避免未定义行为的方法。
回答by π?ντα ?ε?
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.
最好的方法是首先以固定格式(例如uint32_t
网络字节顺序)发送字符串数据的长度。然后接收者可以先读取它并在接收随后发送的序列化消息之前分配适当大小的缓冲区。
sd
and csd
are assumed to be already present socket descriptors.
sd
并且csd
假定已经存在套接字描述符。
Sender.cpp
发件人.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
接收器.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.
缺点是,您在首先发送长度时引入了一种“协议”。
回答by billz
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.
不,std::string::c_str()
返回const char*
这意味着它是只读的。您可以在recv
成功返回后分配本地缓冲区并从本地缓冲区创建字符串对象。
You need to tell recv
function to read a specific length of data, for example you want to read 512 bytes each time:
您需要告诉recv
函数读取特定长度的数据,例如您每次要读取 512 个字节:
#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];
recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);
回答by jww
error: invalid conversion from ‘const void*' to ‘void*' [-fpermissive]
on recv line!
error: invalid conversion from ‘const void*' to ‘void*' [-fpermissive]
在接收线上!
Dialing into this particular question, you wrote (sansthe if
statement):
拨入这个特殊的问题,你写(SANS的if
声明):
bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)
rcv.c_str()
retrieves a const char*
pointer. The const char*
was coerced to the const void*
. The only way I know to get non-const pointer and avoid undefined behavior is taking the address of the first element in a std::string
or std::vector
:
rcv.c_str()
检索一个const char*
指针。将const char*
被强制使用const void*
。我知道获取非常量指针并避免未定义行为的唯一方法是获取 a std::string
or 中第一个元素的地址std::vector
:
bytecount = recv(*csock, &rcv[0], rcv.length(), 0)
Getting the non-const pointer like that is only valid for STL containers that provide contiguous memory. The trick would not work for a map
, multimap
or other associative containers.
像这样获取非常量指针仅对提供连续内存的 STL 容器有效。诀窍就不是一个工作map
,multimap
或其他关联容器。
@π?ντα-?ε? is the only answer that picked up on it, but he did not stress the point.
@π?ντα-?ε? 是唯一得到它的答案,但他没有强调这一点。