【问题标题】:Exception on reading broadcast data with TIdUDPServer (Indy 10) using Delphi 7使用 Delphi 7 使用 TIdUDPServer (Indy 10) 读取广播数据时出现异常
【发布时间】:2012-09-22 08:02:21
【问题描述】:

我在尝试使用 TIdUDPServer 的 OnUDPRead 事件读取从我创建的 IdUDPClient 客户端发送的广播数据时遇到问题。我尝试使用以下问题中显示的示例,但无济于事。

How can I send a broadcast message in Delphi

Reading data with TIdUDPServer

我可以将 TIdUDPServer 绑定到我指定的端口:

procedure TForm1.Button1Click(Sender: TObject);
begin
  IdUDPServer1.BroadcastEnabled := True;
  IdUDPServer1.DefaultPort := StrToInt(edit2.Text);
  IdUDPServer1.Bindings.Add.IP := '0.0.0.0';
  //IdUDPServer1.ThreadedEvent:=True;
  IdUDPServer1.Active := True;
end;

IdUDPServer1UDPRead 已成功触发,表明 UDP 服务器正在工作,但我在这一行出现异常 -> DataStringStream.CopyFrom(AData, AData.Size);

异常:模块中地址 004BA415 的访问冲突 'IndyUDPReceiver.exe'。读取地址 74736574

procedure TForm1.IdUDPServer1UDPRead(Sender: TObject;
  AData: TStream; ABinding: TIdSocketHandle);
var
  DataStringStream: TStringStream;
  msg: string;
begin
  try
    DataStringStream := TStringStream.Create('');
    try
      DataStringStream.CopyFrom(AData, AData.Size);
      msg := DataStringStream.DataString;
      Memo1.Lines.Add(msg);
    finally
      DataStringStream.Free;
    end;
  except
    on E: Exception do
    begin
      Memo1.Lines.Add('Exception:' + E.Message);
      DataStringStream.Free;
    end;
  end;
end;

我已将完整的客户端和服务器上传到:http://www.2shared.com/file/5SRweGIa/Indy_UDP.html

感谢任何指针。 :)

【问题讨论】:

  • 显然试图读取无法读取的内存。上面代码的确切部分导致了这种情况。哪个对象无法读取?您需要使用调试器,可能还需要使用 asm 调试器来找出答案。
  • 是的,在这一行遇到了异常-> DataStringStream.CopyFrom(AData, AData.Size); *** IndyUDPReceiver.exe 项目引发异常类 EAccessViolation,并带有消息“模块“IndyUDPReceiver.exe”中地址 004BA415 的访问冲突。读取地址 74736574'。
  • 哪个对象无法读取?使用 cpu 视图调试 asm。
  • 嗨大卫,这是我得到的 - imageshack.us/a/img12/3053/capturewy.jpg
  • 哪一行是av?

标签: delphi indy indy10


【解决方案1】:

您是否偶然从旧版本的 Delphi 和/或 Indy 升级您的项目,却忘记检查事件处理程序的签名更改? TIdUDPServer.OnUDPRead 事件很久以前就停止使用 TStream 作为其 AData 参数。改为使用TIdBytes

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: TIdBytes; ABinding: TIdSocketHandle);
var
  msg: string;
begin
  msg := BytesToString(AData, Indy8BitEncoding);
  Memo1.Lines.Add(msg);
end;

几周前,我们不得不更改 XE3 的 AData 参数,以最终解决所有 2009+ 版本中 Delphi 和 C++ 之间的 RTTI 不兼容问题:

procedure TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; const AData: array of Byte; ABinding: TIdSocketHandle);
var
  msg: string;
begin
  msg := BytesToString(AData, Indy8BitEncoding);
  Memo1.Lines.Add(msg);
end;

【讨论】:

  • 仅当事件处理程序在运行时在代码中分配时。如果事件处理程序是在旧版本中编写并在设计时分配的,则执行升级,IDE 不太可能验证预先存在的分配并愉快地继续使用它,即使签名不再匹配。正是缺乏验证导致在 Unicode 迁移期间在 Delphi 2009-2010 中创建 STRINGCHECKS 指令,当时基于字符串的事件从 Ansi 切换到 Unicode。必须更新 RTL 以处理不匹配的事件处理程序,尤其是在 C++ 中。
  • 好吧,这很有意义。
  • 因此,在这种情况下,如果事件处理程序签名不匹配但 IDE 仍然接受它(因为 DFM 不是类型安全的),AData 参数将在运行时,但代码会将其解释为 TStream 并在访问错误类型的内存时导致此类异常。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-12
  • 1970-01-01
  • 1970-01-01
  • 2020-12-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多