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

Cat*_*tty 12 c++ sockets string c++11

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

我发送std :: string:

if( (bytecount=send(hsock, input_string.c_str(), input_string.length(),0))== -1)
Run Code Online (Sandbox Code Playgroud)

这可以正确接收吗?

if ((bytecount = recv(*csock, rcv.c_str(), rcv.length(), 0)) == -1)
Run Code Online (Sandbox Code Playgroud)

我收到错误:

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

Ste*_*eve 13

不,它不能. 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). 
Run Code Online (Sandbox Code Playgroud)

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

另请注意使用&buffer[0]而不是buffer.data().获取第一个元素的地址是访问非const指针并避免未定义行为的方法.

  • *//此时我们拥有所有数据.* - "所有数据"到底意味着什么?(对于某人来说,错误地认为你的意思是整个应用程序级别的消息太容易了,这当然是完全错误的.) (4认同)
  • @Catty要接收更多数据,你必须循环并再次调用`recv`.更新的答案. (3认同)
  • 您必须确定要接收的最大数据量并将其定义为长度.您无法知道实际接收的数据量.如果您收到的缓冲区大小小于最大缓冲区大小,则会收到整条消息,否则您需要再次呼叫接收,因为该线路上有更多数据. (2认同)

πάν*_*ῥεῖ 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 
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

缺点是,您在首先发送长度时会引入一种"协议".


bil*_*llz 6

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

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

#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];

recv(*csock, recvbuf, DEFAULT_BUFLEN, 0);
Run Code Online (Sandbox Code Playgroud)