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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 22:07:19  来源:igfitidea点击:

Sending and receiving std::string over socket

c++stringsocketsc++11

提问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::vectorand 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 recvuntil 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_tin 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网络字节顺序)发送字符串数据的长度。然后接收者可以先读取它并在接收随后发送的序列化消息之前分配适当大小的缓冲区。

sdand csdare 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 recvreturns successfully.

不,std::string::c_str()返回const char*这意味着它是只读的。您可以在recv成功返回后分配本地缓冲区并从本地缓冲区创建字符串对象。

You need to tell recvfunction 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 ifstatement):

拨入这个特殊的问题,你写(SANSif声明):

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::stringor std::vector:

rcv.c_str()检索一个const char*指针。将const char*被强制使用const void*。我知道获取非常量指针并避免未定义行为的唯一方法是获取 a std::stringor 中第一个元素的地址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, multimapor other associative containers.

像这样获取非常量指针仅对提供连续内存的 STL 容器有效。诀窍就不是一个工作mapmultimap或其他关联容器。

@π?ντα-?ε? is the only answer that picked up on it, but he did not stress the point.

@π?ντα-?ε? 是唯一得到它的答案,但他没有强调这一点。