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 = newNetwork_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"
 
classNetwork_Listener : public ACE_Event_Handler
{
public:
    Network_Listener (void);
    // Default constructor
    ~Network_Listener (void);
    // Default constructor
   
    virtual inthandle_input (ACE_HANDLEhandle);
    virtual inthandle_close (ACE_HANDLEhandle,
        ACE_Reactor_Maskclose_mask);
    ACE_HANDLEget_handle (void) const;
   
    ACE_INET_Addrlocal_address_;
    ACE_SOCK_Acceptoracceptor_;
};
#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::stringsValidChars = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890~`!@#$%^&*()-_=+{[}]//|;:'/"<,>.?/";
 
#define MAX_PARA 10
classCommand_Line
{
public:
    Command_Line (const char *prog): argc(0)
    {
        memset(buff,0,BUFSIZ);
        strcpy(buff,prog);
        inti;
        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:
    charbuff[BUFSIZ];
    intargc;
    char *argv[MAX_PARA];
};
 
classNetwork_Handler : public ACE_Event_Handler
{
public:
 Network_Handler (ACE_SOCK_Stream &s);
 // Default constructor
 
 virtual inthandle_input (ACE_HANDLEhandle);
 virtual inthandle_close (ACE_HANDLEhandle,
                            ACE_Reactor_Maskclose_mask);
 virtual ACE_HANDLE get_handle (void) const;
 
 ACE_SOCK_Streamstream_;
private:
         void handle_cmd_ls(intargc,char *argv[]);
 intlist_services (void);
 void process_request (ACE_TCHAR *request);
 inline intsend(const char *strSend);
 charcmd[BUFSIZ];
 boolbIsPassword;
};
 
Network_Handler::Network_Handler (ACE_SOCK_Stream &s)
 : stream_ (s)
{
 this->reactor (ACE_Reactor::instance ());
 
 intresult = this->reactor ()->register_handler (this, READ_MASK);
 ACE_ASSERT (result == 0);
 memset(cmd, 0 , sizeof(cmd));
 
 unsigned charbuffer[]={255,251,1,0};//打开客户端回显,主要针对Windows XPtelnet客户端
 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_HANDLEhandle)
{
 //ACE_DEBUG ((LM_DEBUG, "Network_Handler::handle_input handle = %d/n", handle));
 
 //while (1) //不用在这里循环,客户端每输入一个字符,都会激活这个输入事件
    {
      charmessage[BUFSIZ];
      memset(message, 0, BUFSIZ);
      intresult = 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_Linecl(cmd);
                    intargc = cl.GetArgc();
                    char **argv = cl.GetArgv();
                    boolbIsValidCmd = 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)
                        {
                            inti = 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_HANDLEhandle,
                               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 ());
 intresult = 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_HANDLEhandle)
{
 ACE_DEBUG ((LM_DEBUG, "%D Telnet::handle_input handle = %d/n", handle));
 
 ACE_INET_Addrremote_address;
 ACE_SOCK_Streamstream;
 
 // 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.
 intreset_new_handle = this->reactor ()->uses_event_associations ();
 
 intresult = 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_HANDLEhandle,
                                ACE_Reactor_Mask)
{
 ACE_DEBUG ((LM_DEBUG, "%d Telnet::listener_close handle = %d/n", handle));
 
 this->acceptor_.close ();
 
 delete this;
 
 return 0;
}
 
intNetwork_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服务配置器管理的服务列表
intNetwork_Handler::list_services()
{
    ACE_TRACE ("list_services");
    ACE_Service_Repository_Iteratorsri (*ACE_Service_Repository::instance (), 0);
   
    send("Service running state:/r/n");
    inti = 0;
    for (const ACE_Service_Type *sr;
    sri.next (sr) != 0;
    sri.advance ())
    {
        i++;
        charbuff[BUFSIZ];
        sprintf(buff,"#%2.2d %-20s %-10s",
            i,
            sr->name (),
            (sr->active ()) ? "(active)" : "(paused)" );        
       
        if (ACE_OS::strlen(buff) > 0)
        {
            ssize_tn = 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(intargc, char *argv[])
{
    charbuff[BUFSIZ];
         //ACE工具类进行命令行参数分析
    ACE_Get_Optget_opt (argc, argv, ACE_TEXT ("e:s:?"));
    intc;
   
    if (argc > 1)
    {
        while ((c = get_opt ()) != -1)
        {
            switch (c)
            {
            case 'e': //处理-e 参数
                {
                                               //列出某个设备的具体信息
                    intiDevID = ACE_OS::atoi (get_opt.opt_arg ());
                   
                                               //......列出该设备基本配置信息
                }
                break;
            case 's': //处理 -s 参数
                {
                    intiDevID = 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、付费专栏及课程。

余额充值