需要使用 TIdTelnet 与 telnet 服务器交互的示例/演示

发布于 2024-11-15 20:10:40 字数 328 浏览 3 评论 0原文

我尝试使用 Indy 10.5.5(随 Delphi 2010 一起提供)用于:

  • 连接到 telnet 服务器
  • 执行用户名/密码身份验证(获取对命令 shell 的访问权限)
  • 执行命令并将结果数据返回到应用程序

,但没有成功,另外我我完全迷失在 Indy 内部的意大利面条逻辑中,现在不知道为什么它不起作用,也不知道我应该如何将字符串发送到服务器并获取结果。需要一些示例代码来研究。


问题的正式形式:我在哪里可以获得涵盖 TIdTelnet 组件的第 3 方贡献的演示? (indyproject.org 演示网页没有)

I tried to employ Indy 10.5.5 (shipped with Delphi 2010) for:

  • connecting to telnet server
  • performing username/password authentication (gaining access to the command shell)
  • executing a command with returning resulting data back to application

and had no success, additionally i'm completely lost in spaghetti logic of Indy's internals and now have no idea why it didnt work or how i supposed to send strings to the server and grab the results. Need some sample code to study.


Formal form of the question: Where can i get 3-rd party contributed demo covering TIdTelnet component? (indyproject.org demos webpage do not have one)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不打扰别人 2024-11-22 20:10:40

Telnet 的主要问题是它不像大多数其他 Internet 协议那样利用命令/响应模型。任何一方都可以随时发送数据,并且每个方向的数据相互独立。这反映在 TIdTelnet 中,它运行一个内部读取线程来接收数据。因此,您不能像使用其他 Indy 组件那样在单个代码块中简单地连接、发送命令并等待响应。您必须编写命令,然后等待 OnDataAvailable 事件触发,然后解析数据以确定它实际上是什么(并准备好处理可能接收到部分数据的情况,因为这就是 TCP/IP 的工作原理)。

如果您要连接到实际实现命令/响应模型的服务器,那么您最好直接使用 TIdTCPClient 而不是 TIdTelnet (然后手动实现任何 Telnet 序列解码)如果服务器确实使用 Telnet,现在这种情况很少见,但并非不可能)。对于 Indy 11,我们可能会重构 TIdTelnet 的逻辑以支持非线程版本,但这尚未确定。

The main problem with Telnet is that it DOES NOT utilize a command/response model like most other Internet protocols do. Either party can send data at any time, and each direction of data is independant from the other direction. This is reflected in TIdTelnet by the fact that it runs an internal reading thread to receive data. Because of this, you cannot simply connect, send a command, and wait for a response in a single block of code like you can with other Indy components. You have to write the command, then wait for the OnDataAvailable event to fire, and then parse the data to determine what it actually is (and be prepared to handle situations where partial data may be received, since that is just how TCP/IP works).

If you are connecting to a server that actually implements a command/response model, then you are better off using TIdTCPClient directly instead of TIdTelnet (and then implement any Telnet sequence decoding manually if the server really is using Telnet, which is rare nowadays but not impossible). For Indy 11, we might refactor TIdTelnet's logic to support a non-threaded version, but that is undecided yet.

眼眸里的那抹悲凉 2024-11-22 20:10:40

完成印地。
没有评论..只是一些旧代码:-)
telnet 不喜欢发送字符串命令。使用 sendch。

telnetdude.Host := 1.1.1.1;
try
telnetdude.connect;
except
on E: Exception do begin
E.CleanupInstance;
end; {except}
if telnetdude.Connected then begin
for i := 1 to length(StringToSend) do telnetdude.sendch(StringToSend[i]);
telnetdude.sendch(#13);
end;
end; {while}
end; {if}
if telnetdude.Connected then telnetdude.Disconnect;
end;

done with indy.
no comments.. just som old code :-)
telnet don't like the send string kommand.. use sendch.

telnetdude.Host := 1.1.1.1;
try
telnetdude.connect;
except
on E: Exception do begin
E.CleanupInstance;
end; {except}
if telnetdude.Connected then begin
for i := 1 to length(StringToSend) do telnetdude.sendch(StringToSend[i]);
telnetdude.sendch(#13);
end;
end; {while}
end; {if}
if telnetdude.Connected then telnetdude.Disconnect;
end;
卖梦商人 2024-11-22 20:10:40

我希望这可以帮助任何寻找类似问题答案的人。

首先,这似乎是典型的命令/响应模型(如上所述,确实不适用)。

所以我只是让它适用于一些非常简单的应用程序(重新启动我的路由器)。

Johnny Lanewood 对上述代码的具体补充(也许还有一些澄清)
a) 你必须发送#13来确认命令
b) 我发送的每个命令/请求的响应都“挂起”,直到启用 ThreadedEvent。 (这是我的大问题)

c)OnDataAvailable 事件告诉您何时可以从 Telnet 服务器获得新数据 - 但是不能保证这些数据是什么 - 即它与您在命令行中获得的内容/什么都一样附加到之前的回复中。但这不是对您的命令的特定响应行 - 它是 telnet 服务器返回的任何内容(可能是欢迎信息、ASCII 绘图等)。

鉴于上面的 (c),人们宁愿检查 OnDataAvailable 事件并解析数据(知道什么)你会期望的)。当输出停止时(即您需要为此构建一个机制),您可以解析数据并确定服务器是否准备好接受来自客户端的新内容。为了下面的代码的目的,我设置了一个读取超时,并且只使用了 Sleep(2000) - 无知地期望没有错误,并且服务器将在睡眠后准备好执行下一个命令。
我最大的绊脚石是 ThreadedEvent := True (参见上面的 b)

因此,我的工作解决方案(对于特定应用程序,对某些人来说可能很可怕)。

   lIDTelnet := TIdTelnet.Create(nil);
    try
      lIdTelnet.ReadTimeout := 30000;
      lIDTelnet.OnDataAvailable := TDummy.Response;
      lIDTelnet.OnStatus := TDummy.Status;
      lIdTelnet.ThreadedEvent := True;

      try
        lIDTelnet.Connect('192.168.0.1', 23);
        if not lIDTelnet.Connected then
          Raise Exception.Create('192.168.0.1 TELNET Connection Failed');

        Sleep(2000);

        lIdtelnet.SendString(cst_user + #13);
        Sleep(2000);

        lIdtelnet.SendString(cst_pass + #13);
        Sleep(2000);

        lIdtelnet.SendString(cst_reboot + #13);
        Sleep(2000);

        if lIDTelnet.Connected then
           lIDTelnet.Disconnect;
      except
        //Do some handling
      end;
  finally 
    FreeAndNil(lIdTelnet);
  end;

进而

class procedure TDummy.Response(Sender: TIdTelnet; const Buffer: TIdBytes);
begin
  Write(TDummy.ByteToString(Buffer));
end;

class function TDummy.ByteToString(
  const aBytes: TIdBytes): String;
var
  i : integer;
begin
  result := '';
  for i := 0 to Length(aBytes) -1 do
  begin
    result := result + Char(aBytes[i]);
  end;
end;

I hope this helps anyone looking for answers to a similar question.

Firstly, It would seem the typical command/response model (as mentioned above, does indeed NOT apply).

So I just got it working for some very simple application (rebooting my router).

Specific additions to above code from Johnny Lanewood (and perhaps some clarification)
a) You have to send #13 to confirm the command
b) I got "hangs" on every command I sent / response I requested UNTIL I enabled ThreadedEvent. (this was my big issue)

c) the OnDataAvailable event tells you when new data is available from the Telnet Server - however there are no guarantees as to what this data is - i.e. it's pretty what you get in the command line / what ever is appended to the previous responses. But is is NOT a specific response line to your command - it's whatever the telnet server returns (could be welcome info, ASCII drawings etc etc.)

Given (c) above, one would rather check the OnDataAvailable event and parse the data (knowing what you'd expect). When the output stops (i.e. you need build a mechanism for this), you can parse the data and determine whether the server is ready for something new from the client. For the purpose of my code below, I set a read timemout and I just used Sleep(2000) - ignorantly expecting no errors and that the server would be ready after the sleep for the next command.
My biggest stumbling block was ThreadedEvent := True (see above in b)

Thus, my working solution (for specific application, and possibly horrible to some).

   lIDTelnet := TIdTelnet.Create(nil);
    try
      lIdTelnet.ReadTimeout := 30000;
      lIDTelnet.OnDataAvailable := TDummy.Response;
      lIDTelnet.OnStatus := TDummy.Status;
      lIdTelnet.ThreadedEvent := True;

      try
        lIDTelnet.Connect('192.168.0.1', 23);
        if not lIDTelnet.Connected then
          Raise Exception.Create('192.168.0.1 TELNET Connection Failed');

        Sleep(2000);

        lIdtelnet.SendString(cst_user + #13);
        Sleep(2000);

        lIdtelnet.SendString(cst_pass + #13);
        Sleep(2000);

        lIdtelnet.SendString(cst_reboot + #13);
        Sleep(2000);

        if lIDTelnet.Connected then
           lIDTelnet.Disconnect;
      except
        //Do some handling
      end;
  finally 
    FreeAndNil(lIdTelnet);
  end;

and then

class procedure TDummy.Response(Sender: TIdTelnet; const Buffer: TIdBytes);
begin
  Write(TDummy.ByteToString(Buffer));
end;

class function TDummy.ByteToString(
  const aBytes: TIdBytes): String;
var
  i : integer;
begin
  result := '';
  for i := 0 to Length(aBytes) -1 do
  begin
    result := result + Char(aBytes[i]);
  end;
end;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文