在socket上发送和接收std :: string

时间:2013-09-07 07:15:10

标签: c++ string sockets c++11

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

我发送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 个答案:

答案 0 :(得分:11)

不,不能。 c_str()会返回const char*。这意味着您无法覆盖指针的内容。

如果要接收数据,则必须创建缓冲区,例如使用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()。获取第一个元素的地址是访问非const指针并避免未定义行为的方法。

答案 1 :(得分:8)

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

假设

sdcsd已经存在套接字描述符。

<强> 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

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

缺点是,在首先发送长度时,你会引入一种'协议'。

答案 2 :(得分:6)

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

您需要告诉recv函数读取特定长度的数据,例如,您希望每次读取512个字节:

#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];

recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);

答案 3 :(得分:0)

  在recv线上

error: invalid conversion from ‘const void*’ to ‘void*’ [-fpermissive]

拨打这个特定问题,你写了( sans if声明):

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

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

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

获取类似的非const指针仅对提供连续内存的STL容器有效。该技巧不适用于mapmultimap或其他关联容器。

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