如何在Windows中使用升压ASIO异步读取命令行输入? [英] How to asynchronously read input from command line using boost asio in Windows?
问题描述
我发现这个问题,询问如何异步读取输入,但只有会与POSIX流描述符,这将无法在Windows携手。所以,我发现本教程这说明,而是采用了POSIX流描述符,我可以使用的boost :: ASIO:视窗:stream_handle
。
下面两个例子中,我想出了下面的code。当我运行它,我不能输入任何东西进入命令提示符,因为程序立即终止。我想它从用户捕捉任何输入,有可能成为一个的std ::字符串
,同时让我的计划中的其他逻辑来执行(即执行异步I / O从Windows控制台)。
从本质上讲,我试图避免阻塞我的程序,当它试图从标准输入
阅读。我不知道这是否可能在Windows中,我还发现这个帖子其中详细另一个用户遇到试图做同样的事情时,问题
的#define _WIN32_WINNT 0x0501
#定义INPUT_BUFFER_LENGTH 512#包括LT&;&cstdio GT;
#包括LT&;&iostream的GT;#定义BOOST_THREAD_USE_LIB //对于MinGW的4.5 - (https://svn.boost.org/trac/boost/ticket/4878)
#包括LT&;升压/ bind.hpp>
#包括LT&;升压/ asio.hpp>类示例{
上市:
示例(提高:: ASIO :: io_service对象和放大器; io_service对象)
:input_buffer(INPUT_BUFFER_LENGTH),input_handle(io_service对象)
{
//读取一行输入。
提高:: ASIO :: async_read_until(input_handle,input_buffer,为\\ r \\ n,
提高::绑定(&实例:: handle_read,为此,
提高:: ASIO ::占位符::错误
提高:: ASIO ::占位符:: bytes_transferred));
}
无效handle_read(常量的boost ::系统::错误_ code和;错误,的std ::为size_t长度);
无效handle_write(常量的boost ::系统::错误_ code&安培;错误);
私人的:
提高:: ASIO ::流缓冲input_buffer;
提高:: ASIO:视窗:stream_handle input_handle;
};void示例:: handle_read(常量的boost ::系统::错误_ code和;错误,的std ::为size_t长度)
{
如果(!错误)
{
//从输入删除换行符。
input_buffer.consume(1);
input_buffer.commit(长 - 1); 的std :: istream处于(安培; input_buffer);
性病::字符串s;
是>> S; 性病::法院LT&;<小号所述&;&下;的std :: ENDL; 提高:: ASIO :: async_read_until(input_handle,input_buffer,为\\ r \\ n,
提高::绑定(&实例:: handle_read,为此,
提高:: ASIO ::占位符::错误
提高:: ASIO ::占位符:: bytes_transferred));
}
否则,如果(错误==的boost ::支持ASIO ::错误:: NOT_FOUND)
{
性病::法院LT&;< 没有收到结束字符! <<的std :: ENDL;
}
}void示例:: handle_write(常量的boost ::系统::错误_ code&安培;错误)
{
如果(!错误)
{
//读取一行输入。
提高:: ASIO :: async_read_until(input_handle,input_buffer,为\\ r \\ n,
提高::绑定(&实例:: handle_read,为此,
提高:: ASIO ::占位符::错误
提高:: ASIO ::占位符:: bytes_transferred));
}
}INT主(INT ARGC,字符** argv的)
{
尝试{
提高:: ASIO :: io_service对象io_service对象;
例如OBJ(io_service对象);
io_service.run();
}赶上(的std ::例外急症)
{
性病::法院LT&;< e.what()&所述;&下;的std :: ENDL;
}
性病::法院LT&;< 程序已结束<<的std :: ENDL;
的getchar();
返回0;
}
我只花了一两个小时调查这个主题,以便决定后,以prevent别人浪费自己的时间。
Windows不支持IOCP标准输入/输出句柄。当你通过 GetStdHandle(STD_INPUT_HANDLE)手柄
,手柄没有 FILE_FLAG_OVERLAPPED
设置,以便它不支持重叠(异步)IO。但是,即使你
的CreateFile(LCONIN $,
GENERIC_READ,
FILE_SHARE_READ,
空值,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
空值);
WinAPI的只是忽略 dwFlagsAndAttributes
,并再次返回,不支持重叠IO手柄。只有这样,才能获得异步控制台输入的IO /输出是使用与 WaitForSingleObject的
的拉手,0超时,所以你可以检查是否有什么阅读无阻塞。不完全是异步IO,但是能避免多线程,如果它是一个目标。
有关控制台API的更多细节:的https:/ /msdn.microsoft.com/en-us/library/ms686971(v=VS.85).aspx
有什么用 GetStdHandle
和的CreateFile
这里描述返回手柄之间的区别:的 https://msdn.microsoft.com/en-us/library /windows/desktop/ms682075(v=vs.85).aspx 。总之区别只是一个子进程,当的CreateFile
能给访问即使是在父进程重定向其控制台输入缓冲区。
I found this question which asks how to read input asynchronously, but will only work with POSIX stream descriptors, which won't work on Windows. So, I found this tutorial which shows that instead of using a POSIX stream descriptor I can use a boost::asio::windows::stream_handle
.
Following both examples I came up with the code below. When I run it, I cannot type anything into the command prompt, as the program immediately terminates. I'd like it to capture any input from the user, possibly into a std::string
, while allowing other logic within my program to execute (i.e. perform asynchronous I/O from a Windows console).
Essentially, I'm trying to avoid blocking my program when it attempts to read from stdin
. I do not know if this is possible in Windows, as I also found this post which details problems another user encountered when trying to do the same thing.
#define _WIN32_WINNT 0x0501
#define INPUT_BUFFER_LENGTH 512
#include <cstdio>
#include <iostream>
#define BOOST_THREAD_USE_LIB // For MinGW 4.5 - (https://svn.boost.org/trac/boost/ticket/4878)
#include <boost/bind.hpp>
#include <boost/asio.hpp>
class Example {
public:
Example( boost::asio::io_service& io_service)
: input_buffer( INPUT_BUFFER_LENGTH), input_handle( io_service)
{
// Read a line of input.
boost::asio::async_read_until( input_handle, input_buffer, "\r\n",
boost::bind( &Example::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
void handle_read( const boost::system::error_code& error, std::size_t length);
void handle_write( const boost::system::error_code& error);
private:
boost::asio::streambuf input_buffer;
boost::asio::windows::stream_handle input_handle;
};
void Example::handle_read( const boost::system::error_code& error, std::size_t length)
{
if (!error)
{
// Remove newline from input.
input_buffer.consume(1);
input_buffer.commit( length - 1);
std::istream is(&input_buffer);
std::string s;
is >> s;
std::cout << s << std::endl;
boost::asio::async_read_until(input_handle, input_buffer, "\r\n",
boost::bind( &Example::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
else if( error == boost::asio::error::not_found)
{
std::cout << "Did not receive ending character!" << std::endl;
}
}
void Example::handle_write( const boost::system::error_code& error)
{
if (!error)
{
// Read a line of input.
boost::asio::async_read_until(input_handle, input_buffer, "\r\n",
boost::bind( &Example::handle_read, this,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred));
}
}
int main( int argc, char ** argv)
{
try {
boost::asio::io_service io_service;
Example obj( io_service);
io_service.run();
} catch( std::exception & e)
{
std::cout << e.what() << std::endl;
}
std::cout << "Program has ended" << std::endl;
getchar();
return 0;
}
I just spent an hour or two investigating this topic so decided to post to prevent others to waste their time.
Windows doesn't support IOCP for standard input/output handles. When you take the handle by GetStdHandle(STD_INPUT_HANDLE)
, the handle doesn't have FILE_FLAG_OVERLAPPED
set so it doesn't support overlapped (async) IO. But even if you
CreateFile(L"CONIN$",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
NULL);
WinAPI just ignore dwFlagsAndAttributes
and again returns the handle that doesn't support overlapped IO. The only way to get async IO of console input/output is to use the handle with WaitForSingleObject
with 0 timeout so you can check if there's anything to read non-blocking. Not exactly async IO but can avoid multithreading if it's a goal.
More details about console API: https://msdn.microsoft.com/en-us/library/ms686971(v=VS.85).aspx
What's the difference between handles returned by GetStdHandle
and CreateFile
is described here: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075(v=vs.85).aspx. In short the difference is only for a child processes when CreateFile
can give access to its console input buffer even if it was redirected in the parent process.
这篇关于如何在Windows中使用升压ASIO异步读取命令行输入?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!