Я пытаюсь реализовать 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