【问题标题】:Not able to read messages while making tcp ip connection in delphi在delphi中建立tcp ip连接时无法读取消息
【发布时间】:2012-11-21 02:29:53
【问题描述】:

我有在本地机器 (127.0.0.1) 上运行的 exe。此 exe 在端口 1234 写入并在 5678 读取。exe 每 50 秒写入一个整数值,例如 1212、4545、6767 等。我想读取该整数值并显示。所以我使用 Indy Client 来达到这个目的。我为此开发了以下代码 sn-p。

IdTCPClient1.Port  := 1234; //Set port to connect to
IdTCPClient1.Host := '127.0.0.1'; //Set host to connect to
IdTCPClient1.Connect; //Make connection

sMsg := IdTCPClient1.Socket.ReadLn; //Read the response from the server
ShowMessage(sMsg);

但它没有阅读。调试时卡在了一行 (sMsg := IdTCPClient1.Socket.ReadLn;)

当我尝试使用这样的 telnet 命令执行此操作时 远程登录 127.0.0.1 1234 一些杂项或特殊字符在定期间隔后显示,而不是服务器发送的整数值。

请为此提出任何解决方案。

【问题讨论】:

  • 首先,ReadLn 函数在返回之前一直等待,直到它得到一个换行符,如果它是一个普通的换行符还是一个回车符和换行符的组合我不知道。另外,您如何将这些数字作为二进制数据或文本字符串发送?
  • 服务器应用程序仅在 50 秒后发送整数值(电报在 4 字节大块上作为整数值发送)。这是我知道的全部。我应该使用什么来代替 ReadLn?
  • 我不熟悉 Delphi,但我想一个名为 ReadLn 的函数需要文本数据,而不是二进制数据。应该有一些名为 ReadReceive 或类似名称的函数,应该用于任意数据。
  • "strings are null-terminated" 意味着字符串是 c 兼容的,而不是 delphi 兼容的。那么 ReadLn 函数会在这里搜索换行符吗?

标签: delphi sockets tcp delphi-xe2 indy


【解决方案1】:

我不确定您的问题出在哪里,因此,我发布了一个完整示例来创建基本的 Indy 服务器和客户端应用程序。

首先,我有一个带有IdTCPServer 组件和一个按钮的服务器应用程序。相关属性是:

object Button1: TButton
  Text = 'Listen'
  OnClick = Button1Click
end
object IdTCPServer1: TIdTCPServer
  DefaultPort = 1234
  OnExecute = IdTCPServer1Execute
end

服务器上的IdTCPServer.OnExecuteButton.OnClick 方法如下所示:

procedure TServerForm.Button1Click(Sender: TObject);
begin
  IdTCPServer1.Active := not IdTCPServer1.Active;
  if IdTCPServer1.Active then
    Button1.Text := 'Close'
  else
    Button1.Text := 'Listen';
end;

procedure TServerForm.IdTCPServer1Execute(AContext: TIdContext);
var
  Num: Integer;
begin
  while (IdTCPServer1.Active) and (AContext.Connection.Connected) do
  begin
    Num := Random(MaxInt);
    AContext.Connection.IOHandler.WriteLn(IntToStr(Num));
    Sleep(1000);
  end;
end;

如您所见,对于每个连接的客户端,我们将进入一个循环,其中每秒将向套接字写入一个随机数(作为字符串)。

我执行服务器并按下按钮开始监听,接受防火墙警告以允许端口打开,然后我可以成功连接并通过 telnet 从该服务器获取信息:

现在,我创建了客户端应用程序。

表单上的一个Button、Memo和IdTCPClient,相关属性有:

object Button1: TButton
  Text = 'Connect'
  OnClick = Button1Click
end
object Memo1: TMemo
end
object IdTCPClient1: TIdTCPClient
  Host = 'localhost'
  Port = 1234
end

代码如下所示:

procedure TClientForm.ReadResults;
var
  S: string;
begin
  while IdTCPClient1.Connected do
  begin
    S := IdTCPClient1.IOHandler.ReadLn;
    Memo1.Lines.Add(S);
    //don't repeat this approach in production code, it's just a test here
    Application.ProcessMessages;
  end;
end;

procedure TClientForm.Button1Click(Sender: TObject);
begin
  if IdTCPClient1.Connected then
  begin
    IdTCPClient1.Disconnect;
    Button1.Text := 'Connect';
  end
  else
  begin
    IdTCPClient1.Connect;
    Button1.Text := 'Disconnect';
    Button1.Repaint;
    ReadResults;
  end;
end;

在运行时它看起来像这样:

该项目是在 FireMonkey 中使用 Delphi XE3 制作的,但它也应该与支持 Indy 10 的任何 Delphi 版本的 VCL 一起使用。

【讨论】:

  • 感谢 jachguate 发布详细示例。但我的问题是我不知道服务器代码是用哪种语言编写的。我只得到了 exe 文件,我只知道它每 50 秒返回一个整数值,我要做的就是在 delphi xe2 中开发一个应用程序来读取这些整数。
  • 您是否有任何规范文档描述了该数字以何种格式写入。如果它是以二进制格式编写的,那就完全不同了,您必须知道可以使用哪种数据类型来匹配服务器写入的内容,以便在客户端正确实现它。根据您的问题,如果您无法使用 telnet 读取它,或者服务器没有正确写入它或者它是二进制格式 - 您会在 telnet 中获得一些 rare 打印,例如回显二进制文件。
  • 我认为它是二进制格式。请找到我的 telnet 得到响应的屏幕截图docs.google.com/document/d/… 那么,我现在该怎么办。我怎样才能读到这个?
  • 看起来你必须弄清楚你得到了什么(真的根本没有规范?),我建议你阅读所有可用的字节并将其显示为十六进制转储以找出什么你有。之后,尝试将您看到的内容映射到与字节大小和形状相匹配的结构。那是(逆向工程)是一种通过反复试验进行猜测的艺术。
  • 我还有一个提示,你可能得到一些线索或没有:(“字符串以空结尾”意味着字符串与 c 兼容而不是 delphi 兼容。所以 ReadLn 函数将在这里工作,它搜索换行符?
猜你喜欢
  • 1970-01-01
  • 2019-06-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-07
  • 2010-11-03
  • 1970-01-01
  • 2016-11-30
相关资源
最近更新 更多