实现TCP应用程序内置shell的简单方法

simple way of implementing a TCP application built-in shell

本文关键字:简单 方法 shell 内置 TCP 应用程序 实现      更新时间:2023-10-16

我想把我自己的shell嵌入到我的c++可移植应用程序中,它可以通过TCP访问。问题是我真的不知道如何处理控制字符,比如退格键、转义键……我是否应该考虑实现telnet协议?有什么简单的方法可以解决这个问题?

注意:

我知道我在回避"基于意见"的接近理由,但也许存在一种"规范"的方法,被广泛用于解决这个问题。

如果您的目标是实现一个功能齐全的telnet服务器(即类似于Linux提供的服务器,可以运行任意命令行程序,并可以正确处理用户可能想要运行的任何内容,包括像NetHack这样的伪gui程序),那么您将别无选择,只能实现RFC 854的大部分或全部。telnet协议并不简单,但它比许多协议都简单,所以这样做可能没有您想象的那么困难。

另一方面,如果您不需要"完全telnet兼容性";如果只是想为用户提供一种方法来登录到您的程序,向它发送文本命令,并读取结果,那么就简单多了——只需让您的程序在一个众所周知的端口上接受TCP连接(它甚至可以是默认的telnet端口23,尽管这将排除在该端口上运行标准telnet守护进程)。您的程序可以简单地在接受的TCP连接上发送和接收ASCII字符串,这或多或少适用于任何telnet客户端,因为telnet协议被设计为优雅地降级,因此即使连接的一端的程序不响应任何telnet的特殊命令代码,它仍将在基本模式下工作。

盲目地从telnet客户端接收字节的一个小问题是,来自telnet客户端的任何命令代码可能会混淆文本解析器。如果这对您来说是一个问题,您可以执行以下操作,在将数据缓冲区交给程序的文本解析例程之前,将它们从recv()'d数据中过滤出来:

// Rewrites a C character buffer in-place to remove any telnet command-codes from it
// @param buf Pointer to a buffer of data bytes just recv()'d from the telnet client
// @param bufLen The number of valid bytes that (buf) is pointing to
// @returns the number of valid data bytes that (buf) is pointing to after control codes were removed 
int FilterInputBuffer(char * buf, int bufLen)
{
   // persistent state variables, for the case where a telnet command gets split
   // up across several incoming data buffers
   static bool _inSubnegotiation = false;
   static int _commandBytesLeft = 0;
   // Based on the document at http://support.microsoft.com/kb/231866
   static const unsigned char IAC = 255;
   static const unsigned char SB  = 250;
   static const unsigned char SE  = 240;
   char * output = buf;
   for (int i=0; i<bufLen; i++) 
   {
      unsigned char c = buf[i];
      bool keepChar = ((c & 0x80) == 0);
      switch(c)
      {
         case IAC: _commandBytesLeft = 3;                            break;
         case SB:  _inSubnegotiation = true;                         break;
         case SE:  _inSubnegotiation = false; _commandBytesLeft = 0; break;
      }
      if (_commandBytesLeft > 0) {--_commandBytesLeft; keepChar = false;}
      if (_inSubnegotiation) keepChar = false;
      if (keepChar) *output++ = c;  // strip out any telnet control/escape codes
   }
   return (output-buf);  // return new (possibly shorter) data-buffer length
}