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

时间:2014-07-11 14:05:00

标签: c++ c shell sockets tcp

我想将自己的shell嵌入到我的C ++便携式应用程序中,该应用程序可以通过TCP访问。问题是我真的不知道如何处理控制字符,例如退格,逃避......我应该考虑实施,比如telnet协议吗?有什么简单的方法可以解决这个问题?

注:

我知道我正在避开以#34;意见为基础的"关键的原因,但也许存在一个"规范"方式,广泛用于解决这个问题。

1 个答案:

答案 0 :(得分:2)

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

另一方面,如果您不需要“完全telnet兼容性”,而只是想为用户提供登录程序的方法,请向其发送文本命令,并回读结果,即更简单 - 只需让你的程序接受一个众所周知的端口上的TCP连接(它甚至可以是默认的telnet端口,23,尽管这会妨碍在该端口上运行标准的telnet守护进程)。您的程序可以简单地通过接受的TCP连接发送和接收ASCII字符串,这或多或少会与任何telnet客户端一起工作,因为telnet协议旨在优雅地降级,因此即使在基本模式下仍然可以工作连接一端的程序不响应任何telnet的特殊命令代码。

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

// 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
}