如何在Windows中使用升压ASIO异步读取命令行输入? [英] How to asynchronously read input from command line using boost asio in Windows?

查看:359
本文介绍了如何在Windows中使用升压ASIO异步读取命令行输入?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我发现这个问题,询问如何异步读取输入,但只有会与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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆