【发布时间】:2017-01-14 13:38:02
【问题描述】:
[免责声明] 我是新手。
研究 boost::asio 并尝试创建一个具有以下功能的简单异步 TCP 服务器:
- 监听端口 13 上的连接
- 连接后,接收数据
- 如果接收到的数据 == 时间,则返回当前日期时间,否则返回预定义字符串(“请求了其他内容”)
问题: 虽然,我接受连接并接收数据,但在使用 async_send 传输数据时,虽然我没有收到错误并且 bytes_transferred 的值是正确的,但我在客户端收到了空数据。
如果我尝试从handle_accept(而不是handle_read)中传输数据,这可以正常工作。
实施: 我研究了 here 的 boost asio 教程: 实例化一个 tcp_server 对象,它基本上启动接受器并开始监听。如下图:
int main()
{
try
{
boost::asio::io_service io_service;
tcp_server server(io_service);
io_service.run();
}
catch (std::exception& e)
{
std::cerr << e.what() << std::endl;
}
return 0;
}
在 tcp_server 中:
class tcp_server
{
public:
tcp_server(boost::asio::io_service& io_service)
: acceptor_(io_service, tcp::endpoint(tcp::v4(), 13))
{
start_accept();
}
private:
void start_accept()
{
using std::cout;
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
acceptor_.async_accept(new_connection->socket(),
boost::bind(&tcp_server::handle_accept, this, new_connection,
boost::asio::placeholders::error));
cout << "Done";
}
...
}
一旦连接被接受,我将按如下所示进行处理:
void handle_accept(tcp_connection::pointer new_connection,
const boost::system::error_code& error)
{
if (!error)
{
new_connection->start();
}
start_accept();
}
下面是tcp_connection::start()方法:
void start()
{
boost::asio::async_read(socket_, boost::asio::buffer(inputBuffer_),
boost::bind(&tcp_connection::handle_read, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
/* the snippet below works here - but not in handle_read
outputBuffer_ = make_daytime_string();
boost::asio::async_write(socket_, boost::asio::buffer(outputBuffer_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));*/
}
在handle_read:
void handle_read(const boost::system::error_code& error, size_t bytes_transferred)
{
outputBuffer_ = make_daytime_string();
if (strcmp(inputBuffer_, "time"))
{
/*this does not work - correct bytes_transferred but nothing shown on receiving end */
boost::asio::async_write(socket_, boost::asio::buffer(outputBuffer_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else
{
outputBuffer_ = "Something else was requested";//, 128);
boost::asio::async_write(socket_, boost::asio::buffer(outputBuffer_),
boost::bind(&tcp_connection::handle_write, shared_from_this(),
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
handle_write 如下图所示:
void handle_write(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
std::cout << "Bytes transferred: " << bytes_transferred;
std::cout << "Message sent: " << outputBuffer_;
}
else
{
std::cout << "Error in writing: " << error.message();
}
}
请注意以下关于 handle_write 的内容(这真的很奇怪):
- 没有错误
- bytes_transferred 变量的值正确
- outputBuffer_ 的值正确(在 handle_read 中设置)
尽管如此,客户端收到的包 (Packet Sender) 是空的(就数据而言)。
完整代码分享here。
【问题讨论】:
-
当你说你收到空数据时,你的意思是你得到一个完整的 0 字节 (eof) 接收还是 async_read 永远不会完成?为什么不检查处理函数中的错误代码?
-
@RichardHodges 我正在使用“Packet Sender”应用程序作为客户端。查看收到的 tcp 数据包的数据部分,它是空的(没有数据部分)。我想澄清一下,在上面的代码中, inputBuffer_ 是正确的。我没有检查错误,因为我收到了 EOF(我猜这是正常的,已经阅读了整个流)。我将检查除 EOF 之外的所有错误。我还将编辑我的问题以包含 handle_write。
-
小心 asio::async_read 和 eof 错误。 async_read free 函数是一个组合操作。当 bytes_transferred 非零时,它可以指示 eof。在这种情况下,您应该接受数据,然后可选择执行 eof 操作(如果不这样做,您将收到另一个 eof 错误,在下一次读取时传输零字节,因此跳过此可选步骤无关紧要) .
-
只是为了澄清。我的问题不在于 async_read。我收到的很好。问题是在尝试使用 async_write() 从 handler_read 中发送数据时。数据虽然看起来已正确发送,但在接收端不包含任何数据。
标签: c++ sockets boost boost-asio