Delphi UDP打孔:在互联网上并非总是有效

问题描述 投票:1回答:1

我正在尝试使用具有Indy和Firemonkey技术的Delphi实施UDP打孔。

我已尝试遵循此文档:https://www.researchgate.net/publication/1959162_Peer-to-Peer_Communication_Across_Network_Address_Translators

该程序似乎可以运行,但不稳定。

如果我在本地Intranet上的系统上工作,没有问题。如果我在互联网上工作,它并不总是可以工作,我也不知道为什么。

我创建了两个应用程序。

首先是服务器端。每次所有客户端正确连接到服务器。服务器将本地IP和Internet IP对注册在变量(fPeers)中。

我创建了一个IdUDPServer实例。这是“连接按钮”代码:

procedure TForm1.B_ConnectClick(Sender: TObject);
var
  vIdSocketHandle: TIdSocketHandle;
begin
  if IdUDPServer.Active then
  begin
    IdUDPServer.Active := False;
    B_Connect.Text := 'Connect';
  end
  else
  begin
    IdUDPServer.Bindings.Clear;
    vIdSocketHandle := IdUDPServer.Bindings.Add;
    vIdSocketHandle.IP := GStack.LocalAddress;
    vIdSocketHandle.Port := E_POrt.Text.ToInteger;

    IdUDPServer.Active := True;
    B_Connect.Text := 'Disconnect';
  end;
end;

[IdUDPServerUDPRead事件期间,我捕获了连接的客户端的本地和Internet IP地址。在名为fPeerIP的TStringLIST中,添加地址列表。

procedure TForm1.IdUDPServerUDPRead(AThread: TIdUDPListenerThread;
  const AData: TIdBytes; ABinding: TIdSocketHandle);
var vPair: string;
    vData: string;
    vString: string;
    vLog: string;
begin
  vPair := ABinding.PeerIP + ':'+ABinding.PeerPort.ToString;
  vData := BytesToString(AData);
  vLog := '';

  if leftstr(vdata,7) = 'LOCALIP' then
  begin
    vString := vPair+#9+lsExtract(vData,2,',');

    if fPeerIP.IndexOfName(vString) = -1 then
    begin
      fPeerIP.Add(vString);
      M_Peers.Lines.Add(vString);

      vLog := vLog + vString + #13#10;
      IdUDPServer.Send(ABinding.PeerIP, ABinding.PeerPort, 'Peer aggiunto alla lista');
    end;

  end
  else vLog := vData;
end;

在客户端,我创建了一个IdUDPServer实例,该实例在连接时将字符串发送到服务器。

procedure TForm2.B_ConnectClick(Sender: TObject);
var vIdSocketHandle: TIdSocketHandle;
    vLocalAddressList: TIdStackLocalAddressList;
    vI: Integer;
    vSendLIST: TStringLIST;
begin
  if IdUDPServer.Active then
  begin
    Timer.Enabled := False;
    IdUDPServer.Active := False;
    B_Connect.Text := 'Connect';

    M_Networks.Lines.Clear;
    M_Debug.Lines.Clear;
    LB_Peers.Items.Clear;
  end
  else
  begin
    try
      vSendLIST := TStringLIST.Create;
      IdUDPServer.Bindings.Clear;

      vLocalAddressList :=  TIdStackLocalAddressList.Create;
      GStack.GetLocalAddressList(vLocalAddressList);
      M_Networks.Lines.Clear;
      for vI := 0 to vLocalAddressList.Count-1 do
      begin
        if vLocalAddressList.Addresses[vI].IPVersion = id_IPV4 then
        begin
          M_Networks.Lines.Add(vLocalAddressList.Addresses[vI].IPAddress);
          vSendLIST.Add(Format('LOCALIP,%s:%d',[vLocalAddressList.Addresses[vI].IPAddress,E_ClientPort.Text.ToInteger]));
        end;
      end;

      vIdSocketHandle := IdUDPServer.Bindings.Add;
      vIdSocketHandle.Port :=  E_ClientPort.Text.ToInteger;
      vIdSocketHandle.IP := '0.0.0.0';


      IdUDPServer.Active := True;
      for vI := 0 to vSendLIST.Count-1 do
      IdUDPServer.Send(E_Server.Text, E_Port.Text.ToInteger, vSendLIST[vI]);

      B_Connect.Text := 'Disconnect';
      if Assigned(vSendLIST) then FreeAndNil(vSendLIST);
    finally
      if Assigned(vLocalAddressList) then FreeAndnil(vLocalAddressList);
    end;
  end;
end;

也是在客户端,在IdUDPServerUDPRead事件中,我检测对等方列表(服务器发送的功能),并向每个连接的对等方发送一个“ PING”。

我意识到也许我所提供的信息很少。我想知道您的意见,并可能向我指出是否在激活打孔的过程中出错。

谢谢LS

delphi udp firemonkey indy10 hole-punching
1个回答
0
投票

您的代码理论上是正确的,可以在某些NAT路由器上使用,但在其余的路由器上则无法使用

我多年来一直在尝试实现UDP打孔,但这确实很复杂,

您需要将许多NAT遍历机制结合在一起,以使其在大多数情况下都能正常工作

阅读有关STUNTURNICE机制可能会有帮助

© www.soinside.com 2019 - 2024. All rights reserved.