c++ - 带有 boost::asio::read 的 EOF

标签 c++ networking boost client-server boost-asio

我的 C++ 客户端/服务器应用程序有一个小问题。它使用 boost::asio 进行远程通信,使用 Protocol Buffer 进行序列化。这里的客户:

// Time to write
char sizeMessage[20];
string content = request.SerializeAsString();
size_t request_length = content.size();            

boost::asio::write(s, boost::asio::buffer(content.c_str(), request_length));
boost::system::error_code error;

boost::asio::read(s, boost::asio::buffer(sizeMessage, 20));

int bufferSize = atoi(sizeMessage);
char* responseString = new char[bufferSize];        
size_t reply_length = boost::asio::read(s, boost::asio::buffer(responseString, bufferSize), boost::asio::transfer_all(), error);
if(!error){
    response.ParseFromArray((const void*)responseString, reply_length);
    success = true;                
}else{
    response.set_status(ExecResponse::ERROR);                
}


delete[] responseString;

在我的应用程序的这个特定场景中,服务器响应的大小可能会有所不同,从几个字节到几 MB 不等。出于这个原因,服务器首先写入输出的大小,然后我用它来为我的缓冲区分配正确数量的内存。出于某种原因,我在读取数据时出错(总是正确读取大小)。一点点调试显示 asio.misc:2 通过谷歌搜索我发现它是 EOF(实际上读取字节数小于缓冲区大小)。这里是服务器端:

ExecResponse response;
ExecutionServerHandler execHandler(this->sharedData);
execHandler.process(rd, request, response);   
string output = response.SerializeAsString();
//First write the length
ostringstream stringLength;
stringLength << output.size();
response.PrintDebugString();
string lengthString = stringLength.str();    
size_t bw = ba::write(bsocket_, ba::buffer(lengthString));
bw = ba::write(bsocket_, ba::buffer(output));

这实际上是我第一次使用 boost,所以我不是一个经验丰富的开发人员。此外,值得一提的是,在我的应用程序的其他部分,这种机制有效,但我的其他消息有一些不同:尽管它们的大小仍然可变,但它们总是很小(几百字节)。服务器端是相同的,但在客户端我使用的是 boost::asio::transfer_at_least(1) 并且我没有提前写大小。如果我将这些更改应用于这种情况,我注意到读取调用最多可以检索 65536 个字节,但不能更多(过早返回 EOF)。我的开发机器是 64 位的 Debian 5 和 Ubuntu 10.04,我在 Boost 1.40 和 1.47 上得到了相同的行为。如果有人意识到我做错了什么,我很乐意指出来。我拼命想让它发挥作用。

最佳答案

在我看来,您的协议(protocol)中可能存在问题: 您的客户如何知道 lengthString 的长度?您正在将任意数字转换为字符串,然后将其写入缓冲区,而不进行填充或任何操作?如果不查看更多代码,很难看出这一点,但这看起来确实很可疑。

通常,当消息长度可变时,您可以定义某种数据包格式,例如长度字段是 4 个字节(为您的消息选择正确的字节数),然后是消息,然后您可以将(在这种情况下)int 发送到客户端,客户端将首先读取 4 个字节,然后知道还有多少字节从套接字读取。您可能想查看类似 htons 的函数等

如果你有一个可变长度的标题,你将有某种分隔符可以读取。这种类型的 header 在 asio HTTP 示例中进行了说明,其中“\r\n\r\n”是使用的分隔符。此示例也可能对您有用,因为如 reima 所述,您随后需要将客户端更改为先读取 header ,然后再读取消息正文。

关于c++ - 带有 boost::asio::read 的 EOF,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7700310/

相关文章:

c++ - Visual Studio 2012 没有安装 C-Header?

c++ - Win32程序编译但没有窗口出现

c++ - 检查从enable_shared_from_this派生的对象是否由shared_ptr管理?

windows - 我如何知道我的外部 IP 地址是什么?

c++ - 绑定(bind)对象未在 VS2015 上编译

c++ - 神秘构建错误 "symbol(s) not found for i386"- openFrameworks 像素操作

java 转换整数以通过网络发送

Python套接字和测量接收到的字节数

c++ - 直接从 RAM 发送原始数据

c++ - 没有 Boost.System 的 Boost.Asio