(转)ACE环境下为应用提供Telnet服务器

当我们的应用服务运行时,通常没有界面监控运行情况,也不能动态配置一些运行参数。那么我们能不能象Linux那样,提供一个类似shell那样的命令行界面进行交互呢? 当然可以,我们利用ACE的接受器和反应器框架,可以轻易为应用服务搭建一个类shell的远程Telnet环境。
 
主要有两个类实现:
Network_Listener 监听类,打开 TCP 监听端口,准备接受客户端连接
Network_Handler 为每个客户端连接创建的具体处理类,负责 telnet 命令交互
 
在进入反应器主事件循环之前,调用:
       // 打开服务配置器
    ACE_TCHAR * myargv [] = {0, "-f" ,”svc.conf”)};
    if ( ACE_Service_Config :: open (3, //argc,
        myargv , //argv,
        ACE_DEFAULT_LOGGER_KEY ,
        1,
        0,
        1) < 0)
    {
                   … …
}
 
// 创建 telnet 服务监听器
Network_Listener * listener = new Network_Listener ;
 
默认打开的服务端口为 ACE_DEFAULT_SERVER_PORT 20002 ,你可以在 Network_Listener 的构造函数里改变它。
 
具体支持哪些命令,每个命令的含义,可以在 Network_Handler :: handle_input () 函数里定义,该函数已实现了 exit, svc, help 等命令,其中 svc 命令可以动态配置 ace 服务配置器(前提是你先打开它)。另外,你也可以参考 ls 命令扩展你自己的命令集。
 
你还可以扩展现有功能,使它更象一个完整的 shell ,比如支持命令历史等。
 
// Network_Events.h
#ifndef NETWORK_LISTENER_H_
#define NETWORK_LISTENER_H_
#pragma warning ( disable :4786)
 
#include "ace/Reactor.h"
#include "ace/Service_Config.h"
#include "ace/Service_Repository.h"
#include "ace/Service_Types.h"
#include "ace/WFMO_Reactor.h"
#include "ace/INET_Addr.h"
#include "ace/SOCK_Stream.h"
#include "ace/SOCK_Acceptor.h"
#include "ace/OS_main.h"
 
class Network_Listener : public ACE_Event_Handler
{
public:
    Network_Listener (void);
    // Default constructor
    ~ Network_Listener (void);
    // Default constructor
   
    virtual int handle_input ( ACE_HANDLE handle );
    virtual int handle_close ( ACE_HANDLE handle ,
        ACE_Reactor_Mask close_mask );
    ACE_HANDLE get_handle (void) const;
   
    ACE_INET_Addr local_address_ ;
    ACE_SOCK_Acceptor acceptor_ ;
};
#endif
 
 
// Network_Events.cpp,v 4.3 2003/11/05 09:36:08 jwillemsen Exp
//
// ============================================================================
//
// = LIBRARY
//    examples
//
// = FILENAME
//    Network_Events.cpp
//
// = DESCRIPTION
//
//    This application tests Reactor to make sure that it responds
//    correctly to different kinds of network events.
//
//    The test starts off by creating a Network_Listener, that listens
//    for connections at ACE_DEFAULT_SERVER_PORT. When a client
//    connects, a Network_Handler is created. Network_Handler reads
//    messages off the socket and prints them out. This is done until
//    the remote side shuts down. Multiple clients can connect at the
//    same time.
//
//    Events tested in this example includes ACCEPT, READ, and CLOSE masks.
//
//    To run this example, start an instance of this example and
//    connect to it using telnet (to port
//    ACE_DEFAULT_SERVER_PORT(20002)).
//
// = AUTHOR
//    Irfan Pyarali
//
// ============================================================================
 
#include "Network_Events.h"
#include < string >
#include "ace/Get_Opt.h"
 
ACE_RCSID (WFMO_Reactor, Network_Events, "Network_Events.cpp,v 4.3 2007/7/18 Exp" )
const char * strPassPromt = "Password:" ;
const char * strPass = "888" ;
const char * strINMS = "Network Management System/r/n" ;
const char * strVer = "Ver: 2.0/r/n/r/n" ;
const std:: string sValidChars = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~`!@#$%^&*()-_=+{[}]//|;:'/"<,>.?/" ;
 
#define MAX_PARA 10
class Command_Line
{
public:
    Command_Line (const char * prog ): argc (0)
    {
        memset ( buff ,0, BUFSIZ );
        strcpy ( buff , prog );
        int i ;
        for( i = 0; i < strlen ( prog ); i ++)
        {
            if (*( buff + i ) == ' ' )
                *( buff + i ) = 0;
        }
       
        for( i = 0; i < strlen ( prog ); i ++)
        {
            if ((0 == i && buff [ i ] != 0) || ( buff [ i - 1] == 0 && buff [ i ] != 0))
            {
                 argc ++;
                argv [ argc - 1] = buff + i ;
            }
 
            if ( argc > MAX_PARA )
                break;
        }
    }
    virtual ~ Command_Line ()
    {
        /*for(int i=0;i < argc;i++)
        {
            delete argv[i];
        }*/
    }
    inline int GetArgc(){return argc ;}
    inline char **GetArgv(){return argv ;}
private :
    char buff [ BUFSIZ ];
    int argc ;
    char * argv [ MAX_PARA ];
};
 
class Network_Handler : public ACE_Event_Handler
{
public:
  Network_Handler ( ACE_SOCK_Stream & s );
  // Default constructor
 
 virtual int handle_input ( ACE_HANDLE handle );
 virtual int handle_close ( ACE_HANDLE handle ,
                            ACE_Reactor_Mask close_mask );
 virtual ACE_HANDLE   get_handle (void) const;
 
  ACE_SOCK_Stream stream_ ;
private :
         void handle_cmd_ls ( int argc , char * argv []);
  int list_services (void);
 void process_request ( ACE_TCHAR * request );
 inline int send (const char * strSend );
  char cmd [ BUFSIZ ];
  bool bIsPassword ;
};
 
Network_Handler :: Network_Handler ( ACE_SOCK_Stream & s )
 : stream_ ( s )
{
 this-> reactor ( ACE_Reactor :: instance ());
 
  int result = this-> reactor ()-> register_handler (this, READ_MASK);
  ACE_ASSERT ( result == 0);
  memset ( cmd , 0 , sizeof( cmd ));
 
 unsigned char buffer []={255,251,1,0}; // 打开客户端回显,主要针对 Windows XP telnet 客户端
  send (( char *) buffer );
  send ( strINMS );
  send ( strVer );
  send ( strPassPromt );
  bIsPassword = true;
}
 
ACE_HANDLE
Network_Handler :: get_handle (void) const
{
 return this-> stream_ . get_handle ();
}
 
int
Network_Handler :: handle_input ( ACE_HANDLE handle )
{
  //ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_input handle = %d/n", handle));
 
  //while (1) // 不用在这里循环,客户端每输入一个字符,都会激活这个输入事件
    {
      char message [ BUFSIZ ];
      memset ( message , 0, BUFSIZ );
      int result = this-> stream_ . recv_n ( message , 1);
 
      if ( result > 0)
        {
          message [ result ] = 0;
          //ACE_DEBUG ((LM_DEBUG, "Remote message: %s/n", message));
         
         
          if ( message [0] == 8)  // 退格键
          {
              message [0]=8;
              message [1]=32;
              message [2]=8;
             
              if ( strlen ( cmd ) > 0)
              {
                  this-> stream_ . send ( message , 3);
                  cmd [ strlen ( cmd ) - 1] = 0;
              }
          }
          else if ( message [0] == 13)  // 回车符,进行命令处理
          {
              send ( "/r/n" );
 
              if (! bIsPassword && strlen ( cmd ) > 0)
              {
                    Command_Line cl ( cmd );
                    int argc = cl .GetArgc();
                    char ** argv = cl .GetArgv();
                    bool bIsValidCmd = true;
                   
                    if ( strcmp ( argv [0], "help" ) == 0 || strcmp ( argv [0], "?" ) == 0) // 显示帮助
                    {
                         send ( "/r/nCommands    currently supported:/r/n" );
                        send ( "help            list commands currently supported/r/n" );
                        send ( "ls [-e/s DevID] display information of devices/r/n" );
                        send ( "svc xxx         service configure command/r/n" );
                        send ( "exit            exit/r/n" );
                        send ( "/r/n" );
                    }
                    else if ( strcmp ( argv [0], "svc" ) == 0) // 动态配置 ace 服务
                    {
                        if ( argc > 1)
                        {
                            int i = 0;
                            while( cmd [ i ] == ' ' )    i ++;
                            process_request ( cmd + i + ( argv [1] - argv [0]));
                        }
                        else
                        {
                            send ( "/r/nservice configure command:/r/n" );
                            send ( "help          list states of all managed service/r/n" );
                            send ( "reconfigure   reload the service configuration/r/n" );
                            send ( "suspend xxx   suspend service named xxx/r/n" );
                            send ( "resume xxx    resume service named xxx/r/n" );
                            send ( "/r/n" );
                        }
                    }
                    else if ( strcmp ( argv [0], "ls" ) == 0) // 列出设备信息的命令
                    {
                        handle_cmd_ls ( argc , argv ); //ls 命令的处理函数
                    }
                    else if ( strcmp ( argv [0], "exit" ) == 0) // 退出命令
                    {
                        ACE_DEBUG ((LM_DEBUG, "%D Telnet client exited %d/n" , handle ));
                       
                        //linux 下面必须注销 reactor 上的注册,不然阻塞主事件循环
                        this-> reactor ()-> remove_handler (this, READ_MASK);
 
                        this-> stream_ . close ();
                        return 0;
                    }
                    else
                    {
                        bIsValidCmd = false;
                         send ( "unkown command./r/n" );
                        send ( "/r/n" );
                    }
                    if ( bIsValidCmd )
                        ACE_DEBUG ((LM_DEBUG, "%D Telnet Handle %d cmd : %s/n" , handle , cmd ));
              }
             if ( bIsPassword && strcmp ( cmd , strPass ) == 0)
              {
                  send ( "/r/n" );
                  bIsPassword = false;
              }
              memset ( cmd , 0, sizeof( cmd ));
              if ( bIsPassword )
              {
                   send ( strPassPromt );
              }
              else
                  send ( ">" );
          }
          else //ordinary char
          {             
              if ( sValidChars . find ( message ,0,1) != -1)
              {
                  strcat ( cmd , message );
                  if ( bIsPassword )
                  {
                      send ( "*" ); // 密码回显成 *
                  }
                  else
                      this-> stream_ . send ( message , sizeof( message ));
              }
          }
         
        }
      else if ( result == 0)
        {
          ACE_DEBUG ((LM_DEBUG, "%D Telnet client connection closed %d/n" , handle ));
          return -1;
        }
      else if ( errno == EWOULDBLOCK )
        {
          return 0;
        }
     else
        {
          //release 版里面后总是跑到这里来,不知何故
          /*ACE_DEBUG ((LM_DEBUG, "%D Telnet receiving problems, result = %d/n", result));
          return -1;*/
        }
    }
    return 0;
}
 
int
Network_Handler :: handle_close ( ACE_HANDLE handle ,
                               ACE_Reactor_Mask )
{
  ACE_DEBUG ((LM_DEBUG, "%D Telnet::handle_close handle = %d/n" , handle ));
 
#ifdef WIN32
 this-> stream_ . close_writer ();
#endif
 
 this-> stream_ . close ();
 delete this;
 
// ACE_Reactor::end_event_loop ();
 
 return 0;
}
 
Network_Listener :: Network_Listener (void)
 : local_address_ ( ACE_DEFAULT_SERVER_PORT ),
    acceptor_ ( local_address_ , 1)
{
 this-> reactor ( ACE_Reactor :: instance ());
  int result = this-> reactor ()-> register_handler (this,
                                                   ACE_Event_Handler ::ACCEPT_MASK);
  //ACE_ASSERT (result == 0);
}
 
Network_Listener ::~ Network_Listener (void)
{
}
 
ACE_HANDLE
Network_Listener :: get_handle (void) const
{
 return this-> acceptor_ . get_handle ();
}
 
int
Network_Listener :: handle_input ( ACE_HANDLE handle )
{
  ACE_DEBUG ((LM_DEBUG, "%D Telnet::handle_input handle = %d/n" , handle ));
 
  ACE_INET_Addr remote_address ;
  ACE_SOCK_Stream stream ;
 
  // Try to find out if the implementation of the reactor that we are
  // using requires us to reset the event association for the newly
  // created handle. This is because the newly created handle will
  // inherit the properties of the listen handle, including its event
  // associations.
  int reset_new_handle = this-> reactor ()-> uses_event_associations ();
 
  int result = this-> acceptor_ . accept ( stream , // stream
                                       & remote_address , // remote address
                                       0, // timeout
                                       1, // restart
                                       reset_new_handle );  // reset new handler
  ACE_ASSERT ( result == 0);
 
  remote_address . dump ();
 
  Network_Handler * handler ;
  ACE_NEW_RETURN ( handler , Network_Handler ( stream ), -1);
 
  ACE_DEBUG ((LM_DEBUG, "%D Telnet connection from: [%s:%d] %d/n" ,
      remote_address . get_host_addr (),
      remote_address . get_port_number (),
      handler -> get_handle ()));
 
 return 0;
}
 
int
Network_Listener :: handle_close ( ACE_HANDLE handle ,
                                ACE_Reactor_Mask )
{
  ACE_DEBUG ((LM_DEBUG, "%d Telnet::listener_close handle = %d/n" , handle ));
 
 this-> acceptor_ . close ();
 
 delete this;
 
 return 0;
}
 
int Network_Handler :: send (const char * strSend )
{
    return this-> stream_ . send ( strSend , strlen ( strSend ));
}
 
void Network_Handler :: process_request ( ACE_TCHAR * request )
{
    ACE_TRACE ( "process_request" );
    ACE_TCHAR * p ;
   
    // Kill trailing newlines.
    for ( p = request ;
    (* p != '/0' ) && (* p != '/r' ) && (* p != '/n' );
    p ++)
        continue;
   
    * p = '/0' ;
   
    if (ACE_OS:: strcmp ( request , ACE_LIB_TEXT ( "help" )) == 0)
        // Return a list of the configured services.
        list_services ();
    else if (ACE_OS:: strcmp ( request , ACE_LIB_TEXT ( "reconfigure" ) )== 0)
    {
        // Trigger a reconfiguration by re-reading the local <svc.conf> file.
        ACE_Service_Config :: reconfig_occurred (( sig_atomic_t ) 1);
        send ( "Reconfiguration done./r/n/r/n" );
    }
    else
        // Just process a single request passed in via the socket
        // remotely.
        ACE_Service_Config :: process_directive ( request );
   
    // Additional management services may be handled here...
}
 
// 列出 ace 服务配置器管理的服务列表
int Network_Handler :: list_services ()
{
    ACE_TRACE ( "list_services" );
    ACE_Service_Repository_Iterator sri (* ACE_Service_Repository :: instance (), 0);
   
    send ( "Service running state:/r/n" );
    int i = 0;
    for (const ACE_Service_Type * sr ;
    sri . next ( sr ) != 0;
    sri . advance ())
    {
        i ++;
        char buff [ BUFSIZ ];
        sprintf ( buff , "#%2.2d %-20s %-10s" ,
            i ,
            sr -> name (),
            ( sr -> active ()) ? "(active)" : "(paused)" );        
       
        if (ACE_OS:: strlen ( buff ) > 0)
        {
            ssize_t n = send ( buff );
            send ( "/r/n" );
            if ( n <= 0 && errno != EPIPE )
                ACE_ERROR ((LM_ERROR,
                ACE_LIB_TEXT ( "%p/n" ),
                 ACE_LIB_TEXT ( "send_n" )));
        }
    }
    send ( "/r/n" );
 
    return 0;
}
 
// 该函数用来处理命令 ls ,这是一个命令举例,实际应用时应根据自身需要改写或添加命令处理函数
void Network_Handler :: handle_cmd_ls ( int argc , char * argv [])
{
    char buff [ BUFSIZ ];
         // ACE 工具类进行命令行参数分析
    ACE_Get_Opt get_opt ( argc , argv , ACE_TEXT ( "e:s:?" ));
    int c ;
   
    if ( argc > 1)
    {
        while (( c = get_opt ()) != -1)
        {
            switch ( c )
            {
            case 'e' : // 处理 -e 参数
                {
                                               // 列出某个设备的具体信息
                     int iDevID = ACE_OS:: atoi ( get_opt . opt_arg ());
                   
                                               //...... 列出该设备基本配置信息
                }
                break;
            case 's' : // 处理 -s 参数
                {
                    int iDevID = ACE_OS:: atoi ( get_opt . opt_arg ());
                   
                                                 //...... 列出该设备 SNMP 配置信息
                }
                break;
            case '?' :
            default:
                // 如果是 ? 或者其他非法参数,则打出 usage
                send ( "Usage: ls [-e devid] [-s devid]/r/n" );
                break;
            }
        }
    }
    else // 打印全部设备的信息
    {
        sprintf ( buff , "%5s %3s %6s %4s %8s %-15s"
            "%5s %6s/r/n" , "DevID" , "Num" , "Parent" , "Type" , "Protocol" ,
            "IP_ADDR" , "Port" , "Online" );
        send ( buff );
       
                   //...... 列出全部设备信息
    }
    send ( "/r/n" );
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值