【问题标题】:Sending and receiving std::string over socket通过套接字发送和接收 std::string
【发布时间】:2013-09-11 07:45:24
【问题描述】:

我在 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]` 的无效转换!

【问题讨论】:

  • 我编了一个answer 可能对你有帮助。它演示了通过预先发送实际长度来发送任意长度的字符串数据(只需忽略 protobuf 的东西)。
  • @g-makulik:非常感谢! star pkt; 是什么,它适用于 std::string 吗?如果你能写一段代码,我会很高兴的。否则我会尝试自己。
  • star pkt; 是 protobuf 生成类的对象实例。它可以从std::string 对象反序列化/序列化。这些用于通过套接字发送/接收以及应该证明您的需求。
  • 我今天早些时候没有时间为您的案例调整答案。请看一下。

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


【解决方案1】:

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

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

#define DEFAULT_BUFLEN 512
char recvbuf[DEFAULT_BUFLEN];

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

【讨论】:

  • 谢谢,但是本地缓冲区的大小可能是多少?我们需要给它吗?因为我不知道接收值的大小!
  • 我想要不限制缓冲区大小的解决方案!
  • @Catty 你需要设计和实现一个协议(或使用现有的协议)。否则,接收方怎么知道要接收多少字节?
  • @DavidSchwartz:是的,我正试图为我的目的实现协议。但我认为史蒂夫的回答会处理任何大小的数据!
  • @Catty,史蒂夫的答案设置长度为 4096,它不涉及任何大小。
【解决方案2】:

不,它不能。 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,直到没有更多数据为止。

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

【讨论】:

  • 谢谢,std::vector&lt;char&gt; buffer(length) 中的length 是什么,因为我不知道接收数据的具体长度是多少?
  • 您必须确定要接收的最大数据量并将其定义为长度。您无法知道实际收到的数据量。如果您收到的缓冲区小于您的最大缓冲区大小,则您拥有整个消息,否则您需要再次调用接收,因为在线上有更多数据。
  • 我正在处理来自网页的大数据。我怀疑我应该使用它!还有其他方法吗?
  • @Catty 要接收更多数据,您必须循环并再次调用recv。更新了答案。
  • // 此时我们拥有所有数据。 - “所有数据”究竟是什么意思? (人们很容易错误地认为您的意思是整个应用程序级别的消息,这当然是完全不正确的。)
【解决方案3】:

最好的方法是首先以固定格式发送字符串数据的长度(例如网络字节顺序中的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

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

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

【讨论】:

  • +1 用于使用&amp;rcvBuf[0]
【解决方案4】:

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

拨入这个特定的问题,您写道(sansif 声明):

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2011-02-09
    • 2019-10-06
    • 2012-02-12
    • 1970-01-01
    • 2016-12-08
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多