C++ 如何在Windows中使用boost asio从命令行异步读取输入?
我发现它询问如何异步读取输入,但只适用于POSIX流描述符,这在Windows上不起作用。因此,我发现这表明我可以使用C++ 如何在Windows中使用boost asio从命令行异步读取输入?,c++,windows,boost,boost-asio,C++,Windows,Boost,Boost Asio,我发现它询问如何异步读取输入,但只适用于POSIX流描述符,这在Windows上不起作用。因此,我发现这表明我可以使用boost::asio::windows::stream\u句柄来代替POSIX流描述符 根据这两个示例,我得出了下面的代码。当我运行它时,我无法在命令提示符中键入任何内容,因为程序会立即终止。我希望它能够捕获用户的任何输入,可能会捕获到std::string,同时允许执行程序中的其他逻辑(即从Windows控制台执行异步I/O) 本质上,我试图避免在程序试图从stdin读取时阻
boost::asio::windows::stream\u句柄来代替POSIX流描述符
根据这两个示例,我得出了下面的代码。当我运行它时,我无法在命令提示符中键入任何内容,因为程序会立即终止。我希望它能够捕获用户的任何输入,可能会捕获到std::string
,同时允许执行程序中的其他逻辑(即从Windows控制台执行异步I/O)
本质上,我试图避免在程序试图从stdin
读取时阻塞程序。我不知道这在Windows中是否可行,因为我还发现了其他用户在尝试执行相同操作时遇到的详细问题
#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;
}
#定义_WIN32_WINNT 0x0501
#定义输入缓冲区长度512
#包括
#包括
#为MinGW 4.5定义BOOST\u THREAD\u USE\u LIB//(https://svn.boost.org/trac/boost/ticket/4878)
#包括
#包括
课例{
公众:
示例(boost::asio::io_服务和io_服务)
:输入缓冲区(输入缓冲区长度)、输入句柄(io服务)
{
//读一行输入。
boost::asio::异步读取直到(输入句柄、输入缓冲区“\r\n”,
boost::bind(&示例::handle_read,this,
boost::asio::占位符::错误,
boost::asio::占位符::字节(已传输);
}
无效句柄读取(const boost::system::error\u code&error,std::size\u t length);
无效句柄写入(常量boost::system::error\u代码和错误);
私人:
boost::asio::streambuf输入缓冲区;
boost::asio::windows::stream\u handle输入\u handle;
};
无效示例::句柄读取(常量boost::系统::错误代码和错误,std::大小\u t长度)
{
如果(!错误)
{
//从输入中删除换行符。
输入缓冲区消耗(1);
输入缓冲区提交(长度-1);
std::istream是(&input_buffer);
std::字符串s;
是>>s;
std::cout您需要将流句柄初始化为控制台输入句柄。不能将同一个流句柄用于输入和输出,因为这是两个不同的句柄
输入:
Example()
: /* ... */ input_handle( io_service, GetStdHandle(STD_INPUT_HANDLE) )
对于输出,您将使用CONSOLE\u output\u HANDLE
。但这可能有点过头了,您不太可能将需要使用异步写入的那么多数据推送到windows上的标准输出中。您需要调用io\u service::run()
到事件处理循环中进行异步操作
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;
}
我只是花了一两个小时研究这个话题,所以决定发帖子,以防止其他人浪费时间
Windows不支持标准输入/输出句柄的IOCP。当您通过GetStdHandle(STD\u input\u handle)
获取句柄时,句柄没有FILE\u FLAG\u OVERLAPPED
设置,因此它不支持重叠(异步)IO。但即使您
CreateFile(L"CONIN$",
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED | FILE_FLAG_NO_BUFFERING,
NULL);
WinAPI只需忽略dwFlagsAndAttributes
,然后再次返回不支持重叠IO的句柄。获取控制台输入/输出异步IO的唯一方法是将句柄与WaitForSingleObject
一起使用,超时为0,这样您就可以检查是否存在非阻塞读取的内容。不完全是异步IO,但可以避免multith如果这是一个目标,就阅读
有关console API的更多详细信息:
这里描述了GetStdHandle
返回的句柄与CreateFile
返回的句柄之间的区别:。简言之,只有当CreateFile
可以访问其控制台输入缓冲区时,才有区别。我不是Windows用户,但不是我们e\r\n作为新行指示符?是的,但这会阻止它工作吗,因为\n仍在新行序列中?我将delimeter字符串更改为“\r\n”,结果相同。在哪里调用io_服务::run()?io_服务.run()
不会在任何地方被调用,应该吗?正确的位置在哪里?我一定喜欢那些匿名的投票人。这是有道理的,但它会导致抛出一个异常-“分配:句柄无效”。此外,我需要根据MSDN将控制台输入句柄
更改为标准输入句柄
,以便将其编译。感谢您的帮助,山姆。我修改了上面的问题,以包含我现在拥有的完整代码。我合并了您的答案,但现在当我调用该程序时,它会立即返回并成功退出(没有崩溃)。当io_service.run()应该被阻止时,为什么它会返回?@nickb,因为您从未将句柄分配给任何东西,所以您无法从中读取。