C++ 使用async\u read\u时,boost::asio会截断输出吗?
这件事把我难住了 如果使用C++ 使用async\u read\u时,boost::asio会截断输出吗?,c++,boost,boost-asio,C++,Boost,Boost Asio,这件事把我难住了 如果使用async\u read\u直到调用,那么打印出超过4k字节的内容似乎有问题 我有一个小功能,可以打印出100行(刚刚超过4k) 除了注册一个async\u read\u直到回调,在任何组合中都可以正常工作。在这一点上,我的输出被截断到大约4k。但请注意,并非总是如此,有时更少,有时整个内容都会打印出来,这似乎与机器上的负载有关,几乎像是有一些超时?一些asio线程的东西?无论如何,如果我注释掉async\u read\u,直到call,无论我调用printLines多
async\u read\u直到调用,那么打印出超过4k字节的内容似乎有问题
我有一个小功能,可以打印出100行(刚刚超过4k)
除了注册一个async\u read\u直到
回调,在任何组合中都可以正常工作。在这一点上,我的输出被截断到大约4k。但请注意,并非总是如此,有时更少,有时整个内容都会打印出来,这似乎与机器上的负载有关,几乎像是有一些超时?一些asio线程的东西?无论如何,如果我注释掉async\u read\u,直到
call,无论我调用printLines多少次,它都可以正常工作。我甚至可以使用ioService
post
功能,它工作得很好
发生了什么事?顺便说一句,我正在使用linux和amd64机器gcc4.4。(红帽)
使用linux“strace”我得到了更多的线索:
似乎在调用async\u read\u之后,asio使用fcntl调用会导致输出文件描述符改变行为
它会在一段时间后停止打印输出:
选择(4[03],[],[],{300,0})=1(在[0]中,左{2988300000})
readv(0,[{“\n\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0”…,512}],1)=1
写下(2,“这是一个长句子的测试”…,93)=93
写下(2,“这是一个长句子的测试”…,93)=93
... 大约40次
写下(2,“这是一个长句子的测试”…,93)=53
写下(2,“这是一个长句子的测试”…,93)=-1 EAGAIN(资源暂时不可用)
写下(2,“这是一个长句子的测试”…,93)=-1 EAGAIN(资源暂时不可用)
写下(2,“这是一个长句子的测试”…,93)=-1 EAGAIN(资源暂时不可用)
写下(2,“这是一个长句子的测试”…,93)=-1 EAGAIN(资源暂时不可用)
写下(2,“这是一个长句子的测试”…,93)=-1 EAGAIN(资源暂时不可用)
... 剩余部分,直到达到100。
因此,您可以看到select循环正在等待我的输入返回键。然后我们叫我空的
读取处理程序并退出ioService。此时,我调用printLines函数并尝试打印100行,但在打印了40行之后,它就退出了
此EAGAIN的某些内容导致输出停止写入。
如果我在printf没有损坏之前不调用async\u read\u,请再次执行此操作。
我想我知道发生了什么,当我在标准数据文件描述符上请求异步读取模式时,似乎Asio正在将标准数据文件描述符转换为异步非阻塞模式。这就是为什么在一些输出之后,我会在写入时出现EAGAIN错误。当然printf会忽略这些,因此我的输出会被截断。不知道这是Asio中的一个bug还是linux上的一个副作用
下面是我复制问题的简单程序:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <iostream>
using namespace boost::asio;
using namespace std;
io_service ioService;
boost::asio::streambuf inStream;
posix::stream_descriptor input(ioService, STDIN_FILENO);
void printLines()
{
for (int i = 0; i < 100; i++) {
fprintf(stderr, "This is a test of a long sentence, there will be %d more sentences after this on is printed.\n", i);
}
fflush(stderr);
}
void readHandler(const boost::system::error_code& error)
{ // Don't care about read!! }
int main()
{
boost::system::error_code ec;
//printLines(); << this works if uncommented
//ioService.post(printLines); << this works if uncommented
boost::asio::async_read_until(input, inStream, "\n",
bind(readHandler, placeholders::error)); // causes truncated output
cout << "Hit Return to continue..." << endl;
ioService.run_one( ec );
assert(!ec);
printLines(); // partial output if async_read_until is called?
return 0;
}
#包括
#包括
#包括
使用名称空间boost::asio;
使用名称空间std;
io_服务ioService;
boost::asio::streambuf inStream;
posix::流描述符输入(ioService、标准数据文件号);
无效打印行()
{
对于(int i=0;i<100;i++){
fprintf(stderr,“这是对一个长句的测试,在打印此on后将有%d个句子。\n”,i);
}
fflush(stderr);
}
void readHandler(const boost::system::error\u代码和错误)
{//不在乎阅读!!}
int main()
{
boost::system::error_code ec;
//printLines();如果我在printLines
int opt = 0;
ioctl( STDIN_FILENO, FIONBIO, &opt );
printLines();
这种行为是意料之中的
samm@macmini ~> ./a.out
Hit Return to continue...
This is a test of a long sentence, there will be 0 more sentences after this on is printed.
...
This is a test of a long sentence, there will be 96 more sentences after this on is printed.
This is a test of a long sentence, there will be 97 more sentences after this on is printed.
This is a test of a long sentence, there will be 98 more sentences after this on is printed.
This is a test of a long sentence, there will be 99 more sentences after this on is printed.
samm@macmini ~>
虽然我不清楚为什么会发生这种情况,但这可能是主要针对内核/设备的ioctl
的副作用。在各种手册页上浏览时,我没有看到任何描述这种行为的内容。您可以尝试从printLines
中使用fprintf
切换到使用posix::stream\u descriptor
改为标准文件号
编辑:看起来已经有一些改进。Asio可以解决这种行为。特别是
- 为添加了新的非_blocking()函数
管理服务器的非阻塞行为
套接字或描述符
io_control()命令名为
非阻塞io现在在中不推荐使用
支持这些新功能
- 添加了新的本机\u非\u阻塞()
管理
底层网络的非阻塞模式
套接字或描述符。这些函数
旨在允许
任意函数的封装
非阻塞系统调用作为
异步操作
对系统的用户是透明的
套接字对象。函数没有
对动物行为的影响
套接字的同步操作
或描述符
看起来我很感兴趣。我在mac上使用了Boost 1.45来运行您的复制机,这些更改将出现在即将发布的Boost 1.47中。我将尝试获取Chris最新的asio开发版本,看看行为是否发生了变化。您关于非阻塞stderr的理论是合理的。您是否看到在strace o中调用fcntl或ioctl来获取描述符2输出?我在RHEL 6系统上运行了您的复制机,我没有看到EAGAIN,但我确实看到了约60行后的截断输出。我确实注意到当将fprintf更改为std::cerr时,问题消失了。实际上我使用stderr只是为了强制刷新。我真的很有兴趣只使用标准的旧std::cout。实际上,我希望在将来只使用std::cout读取回调处理程序,但这就是它的启动方式。当我尝试在读取处理程序中打印回读取的内容时,它将截断我的输出。我需要某种方法来执行异步读取,但保持标准输出正常(阻塞).Chris使用管道在Asio中完成了很多异步工作,我想知道这是否会影响我的stdout?还有几个问题为什么要将stdin设置为ioctrl,为什么不设置stdout和le