我工作的多线程应用程序,其中一个线程作为从客户端接收命令TCP服务器。 该线程使用升压插座和受体等待客户端连接,从客户端接收的命令,命令传递给应用程序的其余部分,然后再等待。 下面的代码:
void ServerThreadFunc()
{
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port_no));
for (;;)
{
// listen for command connection
tcp::socket socket(io_service);
acceptor.accept(socket);
// connected; receive command
boost::array<char,256> msg_buf;
socket.receive(boost::asio::buffer(msg_buf));
// do something with received bytes here
}
}
此线程花费其大部分时间阻塞调用acceptor.accept()
目前,该线程只被终止的应用程序退出时。 不幸的是,这会导致主()返回后崩溃 - 我相信,因为线程试图单身已被破坏后访问应用程序的记录单。 (这就像当我来到这里,诚实GUV)。
我怎样才能关闭该线向下干净时,它的时间申请退出? 我读过,阻塞接受原始套接字()调用可以从另一个线程关闭套接字被中断,但是这似乎并没有在升压插座工作。 我试着转换服务器逻辑来异步I / O使用升压异步TCP回声服务器的例子 ,但似乎只是换一个阻塞调用acceptor::accept()
用于阻塞调用io_service::run()
,所以我留下了同样的问题:一个阻塞调用,我不能中断。 有任何想法吗?
总之,有两种选择:
- 变化码为异步(
acceptor::async_accept()
和async_read
),经由事件循环中运行io_service::run()
,并通过取消io_service::stop()
- 部队阻止呼叫,以低级别机制,如信号中断。
我建议第一个选项,因为它更可能是便携,更易于维护。 需要理解的重要概念是io_service::run()
唯一只要有挂起的工作块。 当io_service::stop()
被调用时,它会尝试引起阻塞所有线程io_service::run()
,以尽快恢复; 它不会中断同步操作,如acceptor::accept()
和socket::receive()
即使同步操作事件循环中调用。 需要注意的是很重要的io_service::stop()
是一种非阻塞调用,因此同步线程被阻断对io_service::run()
必须使用其他机械,如thread::join()
。
这里是将10秒运行并监听端口8080的例子:
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <iostream>
void StartAccept( boost::asio::ip::tcp::acceptor& );
void ServerThreadFunc( boost::asio::io_service& io_service )
{
using boost::asio::ip::tcp;
tcp::acceptor acceptor( io_service, tcp::endpoint( tcp::v4(), 8080 ) );
// Add a job to start accepting connections.
StartAccept( acceptor );
// Process event loop.
io_service.run();
std::cout << "Server thread exiting." << std::endl;
}
void HandleAccept( const boost::system::error_code& error,
boost::shared_ptr< boost::asio::ip::tcp::socket > socket,
boost::asio::ip::tcp::acceptor& acceptor )
{
// If there was an error, then do not add any more jobs to the service.
if ( error )
{
std::cout << "Error accepting connection: " << error.message()
<< std::endl;
return;
}
// Otherwise, the socket is good to use.
std::cout << "Doing things with socket..." << std::endl;
// Perform async operations on the socket.
// Done using the socket, so start accepting another connection. This
// will add a job to the service, preventing io_service::run() from
// returning.
std::cout << "Done using socket, ready for another connection."
<< std::endl;
StartAccept( acceptor );
};
void StartAccept( boost::asio::ip::tcp::acceptor& acceptor )
{
using boost::asio::ip::tcp;
boost::shared_ptr< tcp::socket > socket(
new tcp::socket( acceptor.get_io_service() ) );
// Add an accept call to the service. This will prevent io_service::run()
// from returning.
std::cout << "Waiting on connection" << std::endl;
acceptor.async_accept( *socket,
boost::bind( HandleAccept,
boost::asio::placeholders::error,
socket,
boost::ref( acceptor ) ) );
}
int main()
{
using boost::asio::ip::tcp;
// Create io service.
boost::asio::io_service io_service;
// Create server thread that will start accepting connections.
boost::thread server_thread( ServerThreadFunc, boost::ref( io_service ) );
// Sleep for 10 seconds, then shutdown the server.
std::cout << "Stopping service in 10 seconds..." << std::endl;
boost::this_thread::sleep( boost::posix_time::seconds( 10 ) );
std::cout << "Stopping service now!" << std::endl;
// Stopping the io_service is a non-blocking call. The threads that are
// blocked on io_service::run() will try to return as soon as possible, but
// they may still be in the middle of a handler. Thus, perform a join on
// the server thread to guarantee a block occurs.
io_service.stop();
std::cout << "Waiting on server thread..." << std::endl;
server_thread.join();
std::cout << "Done waiting on server thread." << std::endl;
return 0;
}
在运行时,我打开两个连接。 下面是输出:
Stopping service in 10 seconds...
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Doing things with socket...
Done using socket, ready for another connection.
Waiting on connection
Stopping service now!
Waiting on server thread...
Server thread exiting.
Done waiting on server thread.
当您收到一个事件,是时候退出,你可以调用acceptor.cancel()
该项目将取消接受(与错误代码operation_canceled
)。 在某些系统上,你可能还需要close()
受体,以及是安全的。
如果说到它,你可以打开本地主机上的临时客户端连接到它 - 将它唤醒。 你甚至可以把它一个特殊的消息,这样就可以从酒馆关闭服务器 - 应该有一个应用程序:)
简单地调用原生手柄和SHUT_RD选项关闭,取消现有的接收(接受)操作。