Delphi UDP Hole Punching: на inte rnet не всегда работает - PullRequest
1 голос
/ 25 февраля 2020

Я пытаюсь реализовать UDP Hole Punching с Delphi с технологией Indy и Firemonkey.

Я пытался следовать этому документу: https://www.researchgate.net/publication/1959162_Peer-to-Peer_Communication_Across_Network_Address_Translators

Программа, кажется, работает, но НЕ стабильна.

Если я работаю в системе с локальным int anet, никаких проблем. Если я работаю с inte rnet, он не всегда работает, и я не знаю почему.

Я создал два приложения.

Первое - на стороне сервера. Каждый раз все клиенты правильно подключаются к серверу. Сервер регистрирует пары Local IP и Inte rnet IP в переменной (fPeers).

Я создал экземпляр IdUDPServer. Это код «Connect pu sh button»:

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 я фиксирую локальный и Inte rnet IP-адреса клиентов, которые подключаются. В TStringLIST с именем fPeerIP я добавляю список адресов.

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

1 Ответ

1 голос
/ 25 февраля 2020

Ваш код теоретически верен и может работать на некоторых маршрутизаторах NAT, но он не будет работать на остальных

Я пытался добиться UDP Hole Punching в течение многих лет, но это действительно сложно,

вам нужно объединить множество механизмов NAT Traversal, чтобы он работал в большинстве случаев

Чтение о STUN , TURN и ICE механизмы могут помочь

...