How to asynchronously read input from command line using boost asio in Windows?

后端 未结 3 1088
萌比男神i
萌比男神i 2020-12-29 14:02

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

相关标签:
3条回答
  • 2020-12-29 14:42

    You need to initialize your stream_handle to the console input handle. You can't use the same stream_handle for input and for output because those are two different handles.

    For input:

        Example()
            : /* ... */ input_handle( io_service, GetStdHandle(STD_INPUT_HANDLE) )
    

    For output you would use CONSOLE_OUTPUT_HANDLE. But that is probably overkill, you're unlikely to be pushing that much data into stdout on windows that you'd need to use an async write.

    0 讨论(0)
  • 2020-12-29 14:49

    You need to invoke io_service::run() to start the event processing loop for asynchronous operations.

    class Example {
        public:
            Example( boost::asio::io_service& io_service )
                : io_service(io_service), input_buffer( INPUT_BUFFER_LENGTH), input_handle( io_service)
            {
            }
            void start_reading();
            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::io_service& io_service;
            boost::asio::streambuf input_buffer;
            boost::asio::windows::stream_handle input_handle;
    };
    
    int main( int argc, char * argv)
    {
        boost::asio::io_service io_service;
        Example obj( io_service );
        obj.start_reading();
    
        io_service.run();
    
        return 0;
    }
    
    0 讨论(0)
  • 2020-12-29 14:50

    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.

    0 讨论(0)
提交回复
热议问题