Recent

Author Topic: Indy UDP packets losses in duplex  (Read 3683 times)

vladbfg

  • New Member
  • *
  • Posts: 12
Indy UDP packets losses in duplex
« on: July 19, 2024, 02:34:30 pm »
Hello all,
Before write module for my project I write simple test using TIdUDPServer.

First, code of sender, that send 2000 packs 50 bytes every 300ms by timer

Code: Pascal  [Select][+][-]
  1. procedure TFmain.UPDSenderTimerTimer(Sender: TObject);
  2.   var i : integer;
  3.     s:string;
  4.     buf : TidBytes;
  5. begin
  6.   s:= #$7E + #0#0#0+#$7E;
  7.   s:= s+#$7E + #0#0#0+#$7E;
  8.   s:=s+s+#0#0#0#0#0;// 10+10+5
  9.   s:=s+s;// 50
  10.  
  11.   buf := bytesof(s);
  12.   for i:=1 to MaxThreads(2000) do begin
  13.     idUDPServer.SendBuffer(EditDebug3.Text, 1003, buf);
  14.     txp := txp+1;
  15.     txb := txb+length(s);
  16.   end;
  17. end;
  18.  

I tested and checked it by Wireshark and all looks like good, I see thousands packets and counts in capture are equal my sended count txp

Second,
I write echo server, it receives pack and send back.

Code: Pascal  [Select][+][-]
  1. procedure TFMain.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  2.   const AData: TIdBytes; ABinding: TIdSocketHandle);
  3.   var sansi : ansistring = '';
  4. begin
  5.   RxB:= RxB + length(AData);
  6.   RxP:= RxP + 1;
  7.  
  8.   lastip := ABinding.PeerIP;
  9.   lastport := ABinding.PeerPort;
  10.  
  11.   SetLength(sansi, Length(AData));
  12.   Move(Pointer(AData)^, Pointer(sansi)^, Length(AData));
  13.  
  14.   Packs.Add(sansi);
  15.   //IdUDPServer1.SendBuffer(ABinding.PeerIP, ABinding.PeerPort, AData);
  16.  
  17. end;

After that, I notice that not all packs are achieved the echo-server. For example I sended 100,000 packs, received 80,000 packs,  but wireshark shows in receive side 100,000packs.

Then I commented  //IdUDPServer1.SendBuffer(ABinding.PeerIP, ABinding.PeerPort, AData);
echo sending and all 100thds packs by rxp  are acheived the aplication|socket.

So, my question is how to make it work in duplex mode?
May be it is nedeed set big buffers or timeouts, separately  TX and RX works fine.


         

cdbc

  • Hero Member
  • *****
  • Posts: 1646
    • http://www.cdbc.dk
Re: Indy UDP packets losses in duplex
« Reply #1 on: July 19, 2024, 03:02:25 pm »
Hi
Define a protocol for your duplex, e.g.: handshakes, ack, nack etc...
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

vladbfg

  • New Member
  • *
  • Posts: 12
Re: Indy UDP packets losses in duplex
« Reply #2 on: July 22, 2024, 06:24:40 am »
Hi
Define a protocol for your duplex, e.g.: handshakes, ack, nack etc...
Regards Benny
What does protocol have to do with it?
There is no protocol (my own protocol, I send raw data over UDP).   
Protocol doesn't matter.
P.S. You probably didn't understand the question- I need to transfer data in both direction simultaneously, simultaneously Rx + Tx.
« Last Edit: July 22, 2024, 06:32:09 am by vladbfg »

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Indy UDP packets losses in duplex
« Reply #3 on: July 22, 2024, 07:33:00 am »
What does protocol have to do with it?
Everything  :)

Quote
There is no protocol (my own protocol, I send raw data over UDP).   
Protocol doesn't matter.
Please read up on UDP f.e. wikipedia

Quote
...
UDP is a connectionless protocol meaning that messages are sent without negotiating a connection and that UDP doesn't keep track of what it has sent.[1][2]
..
Note "connectionless"

Quote
P.S. You probably didn't understand the question- I need to transfer data in both direction simultaneously, simultaneously Rx + Tx.
I think cdbc understood the question as intended but that is just my hunch.

Are you aware that Indy socket implementation uses blocking sockets ?
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

vladbfg

  • New Member
  • *
  • Posts: 12
Re: Indy UDP packets losses in duplex
« Reply #4 on: July 22, 2024, 08:08:22 am »
Quote
...
UDP is a connectionless protocol meaning that messages are sent without negotiating a connection and that UDP doesn't keep track of what it has sent.[1][2]
..
Note "connectionless"
And what?
Did you read my post carefully? ALL packets reach their destination in both directions separately without losses.
Moreover, all packets reach the network card, but do not reach the program (or socket), while I am sending packets (while receiving).

Quote
Are you aware that Indy socket implementation uses blocking sockets ?
Thank you for this. Ok, the socket cannot receive a packet while it is transmitting.
But why is the data lost? Why is the data not accepted into the buffer by the operating system (or socket realization) so that I can pick it up later?



cdbc

  • Hero Member
  • *****
  • Posts: 1646
    • http://www.cdbc.dk
Re: Indy UDP packets losses in duplex
« Reply #5 on: July 22, 2024, 08:14:51 am »
Hi
edit: Answer to your latest Q: UDP doesn't guarantee delivery. TCP does!
If by /simultaneous/, you mean "Sending while receiving", then you need >=2 ports.
Otherwise you can do something like this:
Code: Pascal  [Select][+][-]
  1. procedure TFmain.UPDSenderTimerTimer(Sender: TObject);
  2.   var i : integer;
  3.     s:string;
  4.     buf,MyAck : TidBytes; (* MyAck is the result buffer, to check handshake *)
  5. begin
  6.   s:= #$7E + #0#0#0+#$7E;
  7.   s:= s+#$7E + #0#0#0+#$7E;
  8.   s:=s+s+#0#0#0#0#0;// 10+10+5
  9.   s:=s+s;// 50
  10.  
  11.   buf := bytesof(s);
  12.   for i:=1 to MaxThreads(2000) do begin
  13.     idUDPServer.SendBuffer(EditDebug3.Text, 1003, buf);
  14.     txp := txp+1;
  15.     txb := txb+length(s);
  16.     (* here you read the 'ACK' from the server, the /echo/ in your case*)
  17.     idUDPServer.ReadBuffer(MyAck); // you'd have to figure out how it goes
  18.     (* this would have to be a 'blocking' operation, to avoid overrun, here *)
  19.     (* you check, that the 'ack' is correct, otherwise resend packet till it is *)
  20.   end;
  21. end;
  22.  
Now you should be able to do this:
Code: Pascal  [Select][+][-]
  1. procedure TFMain.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
  2.   const AData: TIdBytes; ABinding: TIdSocketHandle);
  3.   var sansi : ansistring = '';
  4. begin
  5.   RxB:= RxB + length(AData);
  6.   RxP:= RxP + 1;
  7.  
  8.   lastip := ABinding.PeerIP;
  9.   lastport := ABinding.PeerPort;
  10.  
  11.   SetLength(sansi, Length(AData));
  12.   Move(Pointer(AData)^, Pointer(sansi)^, Length(AData));
  13.  
  14.   Packs.Add(sansi);
  15.   (* now the server waits for this to come through, before sending next *)
  16.   IdUDPServer1.SendBuffer(ABinding.PeerIP, ABinding.PeerPort, AData);
  17.  
  18. end;
That's what I mean with "protocol", never mind the rudimentary example...
Regards Benny
« Last Edit: July 22, 2024, 08:17:53 am by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

vladbfg

  • New Member
  • *
  • Posts: 12
Re: Indy UDP packets losses in duplex
« Reply #6 on: July 22, 2024, 08:39:21 am »
Hi
edit: Answer to your latest Q: UDP doesn't guarantee delivery. TCP does!
Even a cat understands this.
 
You suggested using tcp simulation with ack/nack message, ok, but this is not a solution to the problem.
If you use this you will get ping-pong protocol, not full duplex bidirectional stream.

Quote
you mean "Sending while receiving", then you need >=2 ports.
Yes, that's exactly what I meant
I'll say it again: ALL packets reach the network card.
But the packets do not reach the application while the application is sending packets
That's my question, How to fix it without any crutches.
How to configure a socket or OS to accept and remember incoming packets while sending.


Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1428
    • Lebeau Software
Re: Indy UDP packets losses in duplex
« Reply #7 on: July 22, 2024, 09:02:03 am »
First, code of sender, that send 2000 packs 50 bytes every 300ms by timer

Why are you using TIdUDPServer to send the test packets, instead of using TIdUDPClient?

I write echo server, it receives pack and send back.

The correct way to send a reply back to the sender in the OnUDPRead event is to use ABinding.SendTo() instead of TIdUDPServer.SendBuffer().  The ABinding parameter represents the listening socket that actually received the packet and fired the OnUDPRead event, so you should use the same socket to send the reply back.  If you use SendBuffer() instead, it will use the 1st socket in the TIdUDPServer.Bindings collection, which might not be the correct socket if there are multiple bindings defined (such as listening on separate IPv4 + IPv6 sockets, or a separate socket per network interface, etc).

After that, I notice that not all packs are achieved the echo-server. For example I sended 100,000 packs, received 80,000 packs,  but wireshark shows in receive side 100,000packs.

The most likely cause is your server reading packets slower than the sender is sending them, so the listening socket's buffer eventually fills up and discards packets.  Unlike TCP, UDP does not guarantee delivery.  You need to either slow down the rate of the sender, or speed up the rate of the reading, or increase the buffer size of the reader socket so it can hold more packets in cache, eg:

Code: [Select]
for I := 0 to IdUDPServer1.Bindings.Count-1 do begin
  IdUDPServer1.Bindings[I].SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVBUF, 1024*1024*10); // 10MB
end;

So, my question is how to make it work in duplex mode?

It already is. That is not the problem.

May be it is nedeed set big buffers

Most likely.

If by /simultaneous/, you mean "Sending while receiving", then you need >=2 ports.

That is not correct.  A *socket* can send and read at the same time.  A *thread* cannot, and the OnUDPRead event is triggered in a worker thread. But you can multiple bindings running in parallel. And you can have other threads sending while the server is reading.

How to configure a socket or OS to accept and remember incoming packets while sending.

It already does. But it can hold only so many packets by default. If a new packet arrives and the socket's buffer is full, the packet is silently discarded.
« Last Edit: July 22, 2024, 05:42:04 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

cdbc

  • Hero Member
  • *****
  • Posts: 1646
    • http://www.cdbc.dk
Re: Indy UDP packets losses in duplex
« Reply #8 on: July 22, 2024, 09:23:33 am »
Hi
Quote
That is not correct.  A *socket* can send and read at the same time.  A *thread* cannot, and the OnUDPRead event is triggered in a worker thread. But you can multiple bindings running in parallel. And you can have other threads sending while the server is reading.
Thanks Remy, I've learnt something new today  :)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE5 -> FPC 3.2.2 -> Lazarus 2.2.6 up until Jan 2024 from then on it's: KDE5/QT5 -> FPC 3.3.1 -> Lazarus 3.0

vladbfg

  • New Member
  • *
  • Posts: 12
Re: Indy UDP packets losses in duplex
« Reply #9 on: July 22, 2024, 01:07:08 pm »
Code: [Select]
IdUDPServer1.Bindings[0].SetSockOpt(Id_SOL_SOCKET, Id_SO_RCVBUF, 1024*1024*10); // 10MB

Thx!  bingo! it works without losses now.
Thanks very much, Remy .

Quote
The correct way to send a reply back to the sender is to have the OnUDPRead event handler use ABinding.SendTo() instead of TIdUDPServer.SendBuffer().
Is it better/faster?
I watched code, there are such calls:
  sendbuffer(1)-> sendBuffer(2) ->
                  GStack.ResolveHost();
                  Binding.SendTo();
Yes, sendTO faster

« Last Edit: July 22, 2024, 01:35:53 pm by vladbfg »

Remy Lebeau

  • Hero Member
  • *****
  • Posts: 1428
    • Lebeau Software
Re: Indy UDP packets losses in duplex
« Reply #10 on: July 22, 2024, 05:40:37 pm »
Quote
The correct way to send a reply back to the sender is to have the OnUDPRead event handler use ABinding.SendTo() instead of TIdUDPServer.SendBuffer().
Is it better/faster?
I watched code, there are such calls:
  sendbuffer(1)-> sendBuffer(2) ->
                  GStack.ResolveHost();
                  Binding.SendTo();
Yes, sendTO faster

See the update I just made to my previous post.  It is not just a matter of being faster, of also of using correct semantics.
« Last Edit: July 22, 2024, 05:43:29 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

vladbfg

  • New Member
  • *
  • Posts: 12
Re: Indy UDP packets losses in duplex
« Reply #11 on: July 23, 2024, 10:02:13 am »
Why are you using TIdUDPServer to send the test packets, instead of using TIdUDPClient?
Because I need receive/send and packets on both sides sporadically. I don't want use model client-server, both apps acts as "servers" and waits incoming packs, and both can send packs, and uses one port.
[App1] Tx  >> datastream1 >>  Rx[App2]   |   parallel and
[App1] Rx  << datastream2 <<  Tx[App2]  |    asynchronously

Quote
it will use the 1st socket in the TIdUDPServer.Bindings collection, which might not be the correct socket if there are multiple bindings defined
Thx for explanation. I use one binding (which is automatically created upon activation server idudpsrv.active:=true)

Quote
A *thread* cannot, and the OnUDPRead event is triggered in a worker thread. But you can multiple bindings running in parallel. And you can have other threads sending while the server is reading
Is it possible to pass one socket to 2(N) threads and each thread will be able to send data over the same socket? Just interested.


Thaddy

  • Hero Member
  • *****
  • Posts: 16158
  • Censorship about opinions does not belong here.
Re: Indy UDP packets losses in duplex
« Reply #12 on: July 23, 2024, 10:51:04 am »
Are you aware UDP is a potentionally lossy protocol? In other words it is fire and forget? Because that is basically everything where all your questions and possibly misunderstanding come from: UDP has no guaranteed delivery and is not designed like that. It is only fast, but not lossless.
If I smell bad code it usually is bad code and that includes my own code.

TRon

  • Hero Member
  • *****
  • Posts: 3623
Re: Indy UDP packets losses in duplex
« Reply #13 on: July 23, 2024, 11:51:56 am »
The most likely cause is your server reading packets slower than the sender is sending them, so the listening socket's buffer eventually fills up and discards packets.  Unlike TCP, UDP does not guarantee delivery.  You need to either slow down the rate of the sender, or speed up the rate of the reading, or increase the buffer size of the reader socket so it can hold more packets in cache, eg:
Are you aware UDP is a potentionally lossy protocol? In other words it is fire and forget? Because that is basically everything where all your questions and possibly misunderstanding come from: UDP has no guaranteed delivery and is not designed like that. It is only fast, but not lossless.

Besides not guaranteeing delivery and potential loss it also doesn't guarantee order (unless indy has that covered) so depending on what TS actually wants to achieve some sort of protocol is required.
« Last Edit: July 23, 2024, 11:53:45 am by TRon »
This tagline is powered by AI (AI advertisement: Free Pascal the only programming language that matters)

Thaddy

  • Hero Member
  • *****
  • Posts: 16158
  • Censorship about opinions does not belong here.
Re: Indy UDP packets losses in duplex
« Reply #14 on: July 23, 2024, 12:12:59 pm »
Indy does not order UDP packages. That is programmer responsability in the case of UDP.
On very stable networks, with high bandwidth, like in the Netherlands, UDP can achieve near TCP accuracy, but UDP was never meant for that.

https://en.wikipedia.org/wiki/User_Datagram_Protocol#Attributes

Using UDP for streaming real-time audio or video, where a frame drop is not critical, UDP comes alive, but never use it for anything else.
« Last Edit: July 23, 2024, 12:17:45 pm by Thaddy »
If I smell bad code it usually is bad code and that includes my own code.

 

TinyPortal © 2005-2018