【问题标题】:BOOST ASIO - How to write console serverBOOST ASIO - 如何编写控制台服务器
【发布时间】:2011-07-09 19:24:27
【问题描述】:

我必须编写异步 TCP Sever。 TCP Server 必须由控制台管理 (例如:删除客户端、显示所有已连接客户端的列表等)

问题是:如何附加(或编写)控制台,它可以调用上述功能。 这个控制台必须是客户端?我应该将此控制台客户端作为单独的线程运行吗?

我已经阅读了很多教程,但我找不到解决问题的方法。

服务器TCP代码

class ServerTCP
{
public:
   ServerTCP(boost::asio::io_service& A_ioService, unsigned short A_uPortNumber = 13)
      : m_tcpAcceptor(A_ioService, tcp::endpoint(tcp::v4(), A_uPortNumber)), m_ioService (A_ioService)
   {
      start();
   }
private:

   void start()
   {
      ClientSessionPtr spClient(new ClientSession(m_tcpAcceptor.io_service(), m_connectedClients));

      m_tcpAcceptor.async_accept(spClient->getSocket(), 
                                 boost::bind(&ServerTCP::handleAccept, this, spClient, 
                                 boost::asio::placeholders::error));

   }
   void handleAccept(ClientSessionPtr A_spNewClient,  const boost::system::error_code& A_nError)
   {
      if ( !A_nError )
      {
         A_spNewClient->start();
         start();
      }
   }



   boost::asio::io_service& m_ioService;
   tcp::acceptor            m_tcpAcceptor;
   Clients                  m_connectedClients;
};

主要功能:

   try
   {
      boost::asio::io_service ioService;

      ServerTCP server(ioService);
      ioService.run();  
   }
   catch (std::exception& e)
   {
      std::cerr << "Exception: " << e.what() << "\n";
   }

你好,山姆。谢谢你的答复。你能这么好心,给我看一段代码或一些与这个问题有关的例子的链接吗? 大概,我没有正确理解“......单线程服务器......”

事实上,在我想管理服务器操作的“控制台”中,我需要如下所示的 smt:

main()

cout << "Options: q - close server, s - show clients";
while(1)
{
  char key = _getch();
  switch( key )
  {
      case 'q':
         closeServer();
      break
      case 's':
         showClients();
      break
  } 
}

【问题讨论】:

    标签: c++ boost tcp boost-asio


    【解决方案1】:

    问题是:如何附加(或 write) 控制台,可以在上面调用 功能。这个控制台必须 做客户?我应该运行这个控制台 客户端作为单独的线程?

    您不需要单独的线程,使用 posix::stream_descriptorassign STDIN_FILENO 即可。使用async_read 并在读取处理程序中处理请求。

    #include <boost/asio.hpp>
    
    #include <boost/bind.hpp>
    #include <boost/enable_shared_from_this.hpp>
    #include <boost/shared_ptr.hpp>
    
    #include <iostream>
    
    using namespace boost::asio;
    
    class Input : public boost::enable_shared_from_this<Input>
    {
    public:
        typedef boost::shared_ptr<Input> Ptr;
    
    public:
        static void create(
                io_service& io_service
                )
        {
            Ptr input(
                    new Input( io_service )
                    );
            input->read();
        }
    
    private:
        explicit Input(
                io_service& io_service
             ) :
            _input( io_service )
        {
            _input.assign( STDIN_FILENO );
        }
    
        void read()
        {
            async_read(
                    _input,
                    boost::asio::buffer( &_command, sizeof(_command) ),
                    boost::bind(
                        &Input::read_handler,
                        shared_from_this(),
                        placeholders::error,
                        placeholders::bytes_transferred
                        )
                    );
        }
    
        void read_handler(
                const boost::system::error_code& error,
                size_t bytes_transferred
                )
        {
            if ( error ) {
                std::cerr << "read error: " << boost::system::system_error(error).what() << std::endl;
                return;
            }
    
            if ( _command != '\n' ) {
                std::cout << "command: " << _command << std::endl;
            }
    
            this->read();
        }
    
    private:
        posix::stream_descriptor _input;
        char _command;
    };
    
    int
    main()
    {
        io_service io_service;
        Input::create( io_service );
        io_service.run();
    }
    

    【讨论】:

    • 感谢您的回复。你有一些例子的链接吗?实际上在控制台中我需要如下所示: cout
    • Sam,我不认为 OP 实际上想编写一个单独的控制台应用程序来控制服务器,而只是想通过控制台与服务器交互。
    • @Ralf,再次阅读OP的问题后,我相信您是正确的。我已经更新了我的答案。
    • @Sam, + 1 一个优雅而简单的解决方案。我不知道可以使用 posix::stream_descriptor 在 asio 中处理控制台输入。这也适用于 Windows 吗?
    • 谢谢山姆。我可以在 Windows 中使用 posix::stream_descriptor 吗?
    【解决方案2】:

    如果我正确理解 OP,他/她想运行一个通过控制台控制的异步 TCP 服务器,即控制台用作用户界面。 在这种情况下,您不需要单独的客户端应用程序来查询服务器以获取连接的客户端等:

    • 您需要生成一个以某种方式调用 io_service::run 方法的线程。目前,您正在从 main 调用它。由于您的服务器可能会在 main 范围内,因此您需要执行一些操作,例如将 ref 传递给服务器到新线程。 io_service 例如可以是服务器类的成员(除非您的应用程序有其他要求,在这种情况下将服务器和 io_service 都传递给新线程)。
    • 在你的服务器类中添加相应的方法如showClients、closeServer等
    • 确保这些通过控制台触发的调用是线程安全的
    • 在您的 closeServer 方法中,您可以例如调用 io_service::stop 这将导致服务器结束。

    【讨论】:

    • 你好拉尔夫。这正是我所需要的。但是我有很多问题,因为我必须在服务器运行后从控制台读取密钥(命令)。现在我做了“棘手”,我的服务器有 2 个端口。一个端口用于客户端,一个仅用于控制台......并且它可以工作,但我的知识还不够,可能会很快出现一些问题......
    • +1 很好的详细答案。不过,我不认为你 需要 一个单独的线程。您可以使用单个线程来调用io_service::run()。见my answer
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-10-10
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-20
    相关资源
    最近更新 更多