Telnet 连接未将选项卡写入文件
Telnet connection not writing tab to a file
我有一个 C# WPF 应用程序正在建立 Telnet 连接,以便将一些内容从 Windows 系统写入 Linux 系统上的文件。所以说我有一些这样的文字。
Here is a bit\tof text \r\n Followed by a new line.
代码大致如下:
string ipAddress = "11.11.11.11";
int port = 66;
TelnetConnection tc = new TelnetConnection(ipAddress, port);
string s = tc.Login("root", "password", 100);
string prompt = s.TrimEnd();
if (prompt != "$" && prompt != "#"){
throw new Exception("Connection failed");
}
tc.WriteLine("echo $'Here is a bit\tof text \r\n Followed by a new line.' >> MyFile.txt");
这是我使用的 TelnetConnection class:\
enum Verbs
{
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255
}
enum Options
{
SGA = 3
}
class TelnetConnection
{
TcpClient tcpSocket;
int TimeOutMs = 10;
public TelnetConnection(string Hostname, int Port)
{
tcpSocket = new TcpClient(Hostname, Port);
}
public string Login(string Username, string Password, int LoginTimeOutMs)
{
int oldTimeOutMs = TimeOutMs;
TimeOutMs = LoginTimeOutMs;
string s = Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no login prompt");
WriteLine(Username);
s += Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no password prompt");
WriteLine(Password);
s += Read();
TimeOutMs = oldTimeOutMs;
return s;
}
public void WriteLine(string cmd)
{
Write(cmd + "\n");
}
public void Write(string cmd)
{
if (!tcpSocket.Connected) return;
byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("[=11=]xFF", "[=11=]xFF[=11=]xFF"));
tcpSocket.GetStream().Write(buf, 0, buf.Length);
System.Threading.Thread.Sleep(1000);
}
public string Read()
{
if (!tcpSocket.Connected) return null;
StringBuilder sb = new StringBuilder();
do
{
ParseTelnet(sb);
System.Threading.Thread.Sleep(TimeOutMs);
} while (tcpSocket.Available > 0);
return sb.ToString();
}
public bool IsConnected
{
get { return tcpSocket.Connected; }
}
void ParseTelnet(StringBuilder sb)
{
while (tcpSocket.Available > 0)
{
int input = tcpSocket.GetStream().ReadByte();
switch (input)
{
case -1:
break;
case (int)Verbs.IAC:
// interpret as command
int inputverb = tcpSocket.GetStream().ReadByte();
if (inputverb == -1) break;
switch (inputverb)
{
case (int)Verbs.IAC:
//literal IAC = 255 escaped, so append char 255 to string
sb.Append(inputverb);
break;
case (int)Verbs.DO:
case (int)Verbs.DONT:
case (int)Verbs.WILL:
case (int)Verbs.WONT:
// reply to all commands with "WONT", unless it is SGA (suppres go ahead)
int inputoption = tcpSocket.GetStream().ReadByte();
if (inputoption == -1) break;
tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
if (inputoption == (int)Options.SGA)
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO);
else
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
tcpSocket.GetStream().WriteByte((byte)inputoption);
break;
default:
break;
}
break;
default:
sb.Append((char)input);
break;
}
}
}
}
我去查看文件的时候是这样写的
Here is a bitof text
Followed by a new line.
所以制表符甚至没有被读取,但换行是出于某种原因。有什么想法吗?
这实际上很简单,并不是特定于 telnet 的。
打开 Powershell 或 Cmd 并尝试输入您的字符串,您会看到。
命令行将制表符解释为命令完成(auto-complete 最接近的匹配,例如 '>ec\t' 将产生 '>echo'),移动到下一个字段或将制表符扔掉。
您需要将“\t”(针对此特定用途)替换为空格。
标签通常可以通过 telnet 发送。我一直这样做。通常服务器将其解释为移动到下一个字段的请求。
例如 'MyName\tpassword' 将在第一个字段中填写 MyName,然后移至下一个字段并填写密码
这取决于您连接的是什么系统以及那里的 shell 是什么 运行 但您可能需要双重转义标签所以它不仅是 \t
而且 \t
以便将 \
和 t
发送到 shell。但是随后您需要启用 echo 命令以将 \t
解释为不是字符串而是转义 bash 中的 -e
开关完成的。至少在 bash 中应该是这样的。
tc.WriteLine("echo -e \"Here is a bit\tof text \r\n Followed by a new line.\" >> MyFile.txt");
使用更可预测的printf
tc.WriteLine("printf 'Here is a bit\tof text \r\n Followed by a new line.\n' >> MyFile.txt");
您也可以使用xxd
(或类似的)来验证内容
printf 'Here is a bit\tof text \r\n Followed by a new line.\n' | xxd
00000000: 4865 7265 2069 7320 6120 6269 7409 6f66 Here is a bit.of
00000010: 2074 6578 7420 0d0a 2046 6f6c 6c6f 7765 text .. Followe
00000020: 6420 6279 2061 206e 6577 206c 696e 652e d by a new line.
00000030: 0a .
@Johannes Krackowizer 给出了正确答案,但解释中缺少一个细节:'TelnetConnection' 不是文件。您正在做的是向远程计算机键入内容。 @Greg M 也提到了这一点。
当您在字符串中发送 \t
时,您发送的是文字 <tab>
字符。另一端的计算机正在尝试为您完成输入文件名,因为这就是您点击 <tab>
时发生的情况。如果你想取回标签,你需要发送一个 \
和一个 t
。您可以直接发送 t
,但是 \
需要作为 \
发送,因为 \
是转义字符,如您所知。所以发送:
"echo $'Here is a bit\tof text \r\n Followed by a new line.' >> MyFile.txt"
请注意带有两个反斜杠的 bit\tof
。那么为什么 \r\n
有效呢?因为它是 <Enter>
和 <Ctrl>+<Enter>
,而您正在 键入 的字符串是在单引号内键入的。当您使用单引号时,您可以点击 <Enter>
并继续输入直到完成并以最后的 '
.
结束
正如其他人提到的,printf
通常是首选:
"printf $'Here is a bit\tof text \r\n Followed by a new line.\n' >> MyFile.txt"
接下来,在您的代码中,反斜杠也应该被转义,因此您可能还需要转义这些字符:
tc.WriteLine("printf $'Here is a bit\\tof text \r\n Followed by a new line.\n' >> MyFile.txt");
我有一个 C# WPF 应用程序正在建立 Telnet 连接,以便将一些内容从 Windows 系统写入 Linux 系统上的文件。所以说我有一些这样的文字。
Here is a bit\tof text \r\n Followed by a new line.
代码大致如下:
string ipAddress = "11.11.11.11";
int port = 66;
TelnetConnection tc = new TelnetConnection(ipAddress, port);
string s = tc.Login("root", "password", 100);
string prompt = s.TrimEnd();
if (prompt != "$" && prompt != "#"){
throw new Exception("Connection failed");
}
tc.WriteLine("echo $'Here is a bit\tof text \r\n Followed by a new line.' >> MyFile.txt");
这是我使用的 TelnetConnection class:\
enum Verbs
{
WILL = 251,
WONT = 252,
DO = 253,
DONT = 254,
IAC = 255
}
enum Options
{
SGA = 3
}
class TelnetConnection
{
TcpClient tcpSocket;
int TimeOutMs = 10;
public TelnetConnection(string Hostname, int Port)
{
tcpSocket = new TcpClient(Hostname, Port);
}
public string Login(string Username, string Password, int LoginTimeOutMs)
{
int oldTimeOutMs = TimeOutMs;
TimeOutMs = LoginTimeOutMs;
string s = Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no login prompt");
WriteLine(Username);
s += Read();
if (!s.TrimEnd().EndsWith(":"))
throw new Exception("Failed to connect : no password prompt");
WriteLine(Password);
s += Read();
TimeOutMs = oldTimeOutMs;
return s;
}
public void WriteLine(string cmd)
{
Write(cmd + "\n");
}
public void Write(string cmd)
{
if (!tcpSocket.Connected) return;
byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("[=11=]xFF", "[=11=]xFF[=11=]xFF"));
tcpSocket.GetStream().Write(buf, 0, buf.Length);
System.Threading.Thread.Sleep(1000);
}
public string Read()
{
if (!tcpSocket.Connected) return null;
StringBuilder sb = new StringBuilder();
do
{
ParseTelnet(sb);
System.Threading.Thread.Sleep(TimeOutMs);
} while (tcpSocket.Available > 0);
return sb.ToString();
}
public bool IsConnected
{
get { return tcpSocket.Connected; }
}
void ParseTelnet(StringBuilder sb)
{
while (tcpSocket.Available > 0)
{
int input = tcpSocket.GetStream().ReadByte();
switch (input)
{
case -1:
break;
case (int)Verbs.IAC:
// interpret as command
int inputverb = tcpSocket.GetStream().ReadByte();
if (inputverb == -1) break;
switch (inputverb)
{
case (int)Verbs.IAC:
//literal IAC = 255 escaped, so append char 255 to string
sb.Append(inputverb);
break;
case (int)Verbs.DO:
case (int)Verbs.DONT:
case (int)Verbs.WILL:
case (int)Verbs.WONT:
// reply to all commands with "WONT", unless it is SGA (suppres go ahead)
int inputoption = tcpSocket.GetStream().ReadByte();
if (inputoption == -1) break;
tcpSocket.GetStream().WriteByte((byte)Verbs.IAC);
if (inputoption == (int)Options.SGA)
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WILL : (byte)Verbs.DO);
else
tcpSocket.GetStream().WriteByte(inputverb == (int)Verbs.DO ? (byte)Verbs.WONT : (byte)Verbs.DONT);
tcpSocket.GetStream().WriteByte((byte)inputoption);
break;
default:
break;
}
break;
default:
sb.Append((char)input);
break;
}
}
}
}
我去查看文件的时候是这样写的
Here is a bitof text
Followed by a new line.
所以制表符甚至没有被读取,但换行是出于某种原因。有什么想法吗?
这实际上很简单,并不是特定于 telnet 的。
打开 Powershell 或 Cmd 并尝试输入您的字符串,您会看到。
命令行将制表符解释为命令完成(auto-complete 最接近的匹配,例如 '>ec\t' 将产生 '>echo'),移动到下一个字段或将制表符扔掉。
您需要将“\t”(针对此特定用途)替换为空格。
标签通常可以通过 telnet 发送。我一直这样做。通常服务器将其解释为移动到下一个字段的请求。
例如 'MyName\tpassword' 将在第一个字段中填写 MyName,然后移至下一个字段并填写密码
这取决于您连接的是什么系统以及那里的 shell 是什么 运行 但您可能需要双重转义标签所以它不仅是 \t
而且 \t
以便将 \
和 t
发送到 shell。但是随后您需要启用 echo 命令以将 \t
解释为不是字符串而是转义 bash 中的 -e
开关完成的。至少在 bash 中应该是这样的。
tc.WriteLine("echo -e \"Here is a bit\tof text \r\n Followed by a new line.\" >> MyFile.txt");
使用更可预测的printf
tc.WriteLine("printf 'Here is a bit\tof text \r\n Followed by a new line.\n' >> MyFile.txt");
您也可以使用xxd
(或类似的)来验证内容
printf 'Here is a bit\tof text \r\n Followed by a new line.\n' | xxd
00000000: 4865 7265 2069 7320 6120 6269 7409 6f66 Here is a bit.of
00000010: 2074 6578 7420 0d0a 2046 6f6c 6c6f 7765 text .. Followe
00000020: 6420 6279 2061 206e 6577 206c 696e 652e d by a new line.
00000030: 0a .
@Johannes Krackowizer 给出了正确答案,但解释中缺少一个细节:'TelnetConnection' 不是文件。您正在做的是向远程计算机键入内容。 @Greg M 也提到了这一点。
当您在字符串中发送 \t
时,您发送的是文字 <tab>
字符。另一端的计算机正在尝试为您完成输入文件名,因为这就是您点击 <tab>
时发生的情况。如果你想取回标签,你需要发送一个 \
和一个 t
。您可以直接发送 t
,但是 \
需要作为 \
发送,因为 \
是转义字符,如您所知。所以发送:
"echo $'Here is a bit\tof text \r\n Followed by a new line.' >> MyFile.txt"
请注意带有两个反斜杠的 bit\tof
。那么为什么 \r\n
有效呢?因为它是 <Enter>
和 <Ctrl>+<Enter>
,而您正在 键入 的字符串是在单引号内键入的。当您使用单引号时,您可以点击 <Enter>
并继续输入直到完成并以最后的 '
.
正如其他人提到的,printf
通常是首选:
"printf $'Here is a bit\tof text \r\n Followed by a new line.\n' >> MyFile.txt"
接下来,在您的代码中,反斜杠也应该被转义,因此您可能还需要转义这些字符:
tc.WriteLine("printf $'Here is a bit\\tof text \r\n Followed by a new line.\n' >> MyFile.txt");