【发布时间】:2021-01-18 10:21:11
【问题描述】:
我尝试按照this 和this 示例创建带有zlib 压缩的简单回显服务器。
我的想法是现在发送一些字符串,因为我可以在发送之前将 POD 类型转换为字符串 (std::string(reinterpret_cast<const char *>(&pod), sizeof(pod))),这样我才能确定传输层工作正常。
这里有一个问题。客户端压缩数据,发送它并说数据已发送,但服务器在读取数据时被阻止。我不明白为什么会这样。
我尝试使用operator<< 和out.flush(),也尝试使用boost::iostreams::copy()。结果是一样的。代码示例是(我根据参数为服务器和客户端使用相同的源文件):
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/copy.hpp>
#include <boost/asio.hpp>
#include <iostream>
#include <sstream>
namespace ip = boost::asio::ip;
using ip::tcp;
const unsigned short port = 9999;
const char host[] = "127.0.0.1";
void receive()
{
boost::asio::io_context ctx;
tcp::endpoint ep(ip::address::from_string(host), port);
tcp::acceptor a(ctx, ep);
tcp::iostream stream;
a.accept(stream.socket());
std::stringstream buffer;
std::cout << "start session" << std::endl;
try
{
for (;;)
{
{
boost::iostreams::filtering_istream in;
in.push(boost::iostreams::zlib_decompressor());
in.push(stream);
std::cout << "start reading" << std::endl;
// looks like server is blocked here
boost::iostreams::copy(in, buffer);
}
std::cout << "data: " << buffer.str() << std::endl;
{
boost::iostreams::filtering_ostream out;
out.push(boost::iostreams::zlib_compressor());
out.push(stream);
boost::iostreams::copy(buffer, out);
}
std::cout << "Reply is sended" << std::endl;
}
}
catch(const boost::iostreams::zlib_error &e)
{
std::cerr << e.what() << e.error() << '\n';
stream.close();
}
}
void send(const std::string &data)
{
tcp::endpoint ep(ip::address::from_string(host), port);
tcp::iostream stream;
stream.connect(ep);
std::stringstream buffer;
buffer << data;
if (!stream)
{
std::cerr << "Cannot connect to " << host << ":" << port << std::endl;
return;
}
try
{
{
boost::iostreams::filtering_ostream out;
out.push(boost::iostreams::zlib_compressor());
out.push(stream);
out << buffer.str();
out.flush();
}
std::cout << "sended: " << data << std::endl;
buffer.str("");
{
boost::iostreams::filtering_istream in;
in.push(boost::iostreams::zlib_decompressor());
in.push(stream);
// looks like client is blocked here
boost::iostreams::copy(in, buffer);
}
std::cout << "result: " << buffer.str() << std::endl;
}
catch(const boost::iostreams::zlib_error &e)
{
std::cerr << e.what() << '\n';
}
}
int main(int argc, const char *argv[])
{
if (argc > 1 && argv[1] == std::string("sender"))
send("hello world");
else
receive();
return 0;
}
首先我启动服务器,然后我启动客户端。产生以下输出:
服务器
$ ./example
# now it waits while client will be accepted
start session
start reading
客户
$ ./example sender
sended: hello world
程序被上面的输出阻塞。我猜服务器仍在等待来自客户端的数据,并且它不知道客户端发送了它所拥有的所有内容。
如果我使用Ctrl + C 关闭客户端,则输出如下:
$ ./example
# now it waits while client will be accepted
start session
start reading
# now it is blocked until I press Ctrl + C
data: hello world
Reply is sended
start reading
zlib error-5
和
$ ./example sender
sended: hello world
^C
我猜zlib error-5 是因为服务器认为存档不完整。
预期行为没有阻塞。当客户端启动时,该消息必须出现在服务器程序输出中。
为什么程序无法读取?我该如何解决?
【问题讨论】:
-
接收者应该如何知道消息的长度?您必须对某种未压缩的消息长度进行编码,才能知道何时停止阅读并实际解压缩到目前为止收到的内容。
-
我认为这应该由
zlib_compressor完成。如果它获取数据,那么它会打包数据(我们得到一个存档对象),tcp::iostream对象通过网络发送存档对象。并且接收者获取具有大小的存档对象,不是吗?如果我错了,请纠正我
标签: c++ boost boost-asio boost-iostreams