16

我在 SO 上看到过类似的问题,但没有回答我的问题。在这里,我正在尝试发送和接收字符串:

我正在发送 std::string :

if( (bytecount=send(hsock, input_string.c_str(), input_string.length(),0))== -1)

它可以被正确接收吗?

if ((bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)) == -1)

我收到错误:

错误:recv 行上从 'const void*' 到 'void*' [-fpermissive]` 的无效转换!

4

4 回答 4

18

不,它不能。 c_str()返回一个const char*. 这意味着您不能覆盖指针的内容。

如果您想接收数据,您必须创建一个缓冲区,例如使用 a std::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). 

上面的代码一次将接收 4096 个字节。如果发送的数据超过 4K,它将继续循环并追加数据,recv直到没有更多数据为止。

还要注意使用&buffer[0]代替buffer.data()。获取第一个元素的地址是访问非常量指针并避免未定义行为的方法。

于 2013-09-07T07:24:31.887 回答
17

最好的方法是首先以固定格式(例如uint32_t网络字节顺序)发送字符串数据的长度。然后接收者可以先读取它并分配适当大小的缓冲区,然后再接收随后发送的序列化消息。

sd并且csd假定已经存在套接字描述符。

发件人.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 

接收器.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

优点是。您不必弄乱多个缓冲读取并复制到接收到的字符串。此外,您将在接收方知道发送的数据何时最终完成。

缺点是,您在首先发送长度时引入了一种“协议”。

于 2013-09-07T21:21:50.087 回答
6

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);
于 2013-09-07T07:21:20.543 回答
0

error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]在recv线上!

拨入这个特定问题,您写道(没有声明if):

bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)

rcv.c_str()检索一个const char*指针。被const char*胁迫到const void*. 我知道获取非常量指针并避免未定义行为的唯一方法是获取 a std::stringor中第一个元素的地址std::vector

bytecount = recv(*csock, &rcv[0], rcv.length(), 0)

像这样获取非常量指针仅对提供连续内存的 STL 容器有效。该技巧不适用于 amapmultimap其他关联容器。

@πάντα-ῥεῖ 是唯一的答案,但他没有强调这一点。

于 2018-01-03T01:57:12.733 回答