Я хотел бы встроить свою собственную оболочку в свое портативное приложение C++, которое будет доступно через TCP. Проблема в том, что я не знаю, как обрабатывать управляющие символы, такие как backspace, escape... Должен ли я изучать реализацию, скажем, протокола telnet? Какой простой способ решить эту проблему?
ЗАМЕТКА:
Я знаю, что я обойду "основанную на мнениях" близкую причину, но, возможно, существует "канонический" способ, который широко используется для решения этой проблемы.
Если ваша цель - реализовать полностью функциональный сервер telnet (то есть аналогичный тому, который предоставляется Linux, который может запускать произвольные программы командной строки и может корректно обрабатывать все, что может потребоваться пользователю, включая программы псевдо-GUI, такие как NetHack) то у вас не будет выбора, кроме как реализовать большинство или все RFC 854. Протокол telnet не является тривиальным, но он проще, чем множество протоколов, поэтому это может быть не так сложно, как вы думаете.
С другой стороны, если вам не нужна "полная совместимость с telnet", а просто хотите предоставить пользователю возможность войти в вашу программу, отправить ему текстовые команды и прочитать результаты, что намного проще - только ваша программа принимает TCP-соединения на хорошо известном порту (это может быть даже порт telnet по умолчанию 23, хотя это предотвратит запуск стандартного демона telnet на этом порту). Ваша программа может просто отправлять и получать строки ASCII по принятому TCP-соединению (-ам), и это будет более или менее работать с любым 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
}