Recent

Author Topic: lnet udp how to exit gracefully  (Read 949 times)

lado

  • New Member
  • *
  • Posts: 12
lnet udp how to exit gracefully
« on: May 06, 2023, 06:00:03 am »
I am creating a (simple) forms app that reads and decodes UDP (ipv4) packets. I do that by placing TLUDPComponent (named udp1)on the form, then starting the UDP by
Quote
 
udp1.Connect('0.0.0.0', 2237);
udp1.Listen();
I got most of the things working OK, but I have an issue when I need to quit/close the udp connection and exit the program. I have tried a few things but always ended up with External:ACCESS VIOLATION error. I went through lnet examples trying to figure out how to properly do it but failed so far. My last (unsuccessful) attempt looks like this (it makes no difference if I put True or False value to Disconnect):
Quote
  if udp1.Connected then
  begin
     udp1.Disconnect(True);
     udp1.Destroy;
  end;
  Halt;
I am looking not just for help solving this, but I'd like if someone can point me to an explanation but why & how to do it ..

TRon

  • Hero Member
  • *****
  • Posts: 2537
Re: lnet udp how to exit gracefully
« Reply #1 on: May 06, 2023, 06:08:40 am »
By placing the component on the form the component is created with the form as owner. That means that the form now takes care of destroying the component whenever the form is destroyed.

so in your code when you do:
Code: Pascal  [Select][+][-]
  1. udp1.Destroy;
The instance of the component is freed from memory. When the form itself is being freed it tries to free that instance (again), resulting in an access violation.

iow, please don't do that  ;D

edit: As an additional note. Never call halt in a Lazarus GUI application unless it is really meant as a panic exit of your application. Using halt in GUI applications usually causes memory leaks.
« Last Edit: May 06, 2023, 06:26:48 am by TRon »

lado

  • New Member
  • *
  • Posts: 12
Re: lnet udp how to exit gracefully
« Reply #2 on: May 06, 2023, 07:03:00 am »
Hmm..
I thought that quitting the form would gracefully quit the UDP connection too. Unfortunately when I just quit the form, the (dreaded) External:ACCESS VIOLATION happened and that's why I tried to do it myself thus making it worse ...
You're saying that using a Halt is a no, no. Form's Close trigger the same error! What's the correct way?
Well, I guess I'll have dumb the program down until it basically works OK, then I'll add the needed logic step by step until I (hopefully) find the culprit.
Anyway, thanks for the explanation.
« Last Edit: May 06, 2023, 07:11:28 am by lado »

TRon

  • Hero Member
  • *****
  • Posts: 2537
Re: lnet udp how to exit gracefully
« Reply #3 on: May 06, 2023, 08:45:47 am »
In the lnet OPM package exist a directory with examples that you could take a look at how to use the different lnet components. If you are creating a GUI application then have a look at the examples/visual directory. There you can also find an example in the directory tcpudp that uses the udp component.

lado

  • New Member
  • *
  • Posts: 12
Re: lnet udp how to exit gracefully
« Reply #4 on: May 06, 2023, 10:34:28 am »
Sadly, I've had a look at those examples, specifically the tcp/udp one. I just wasn't successful in reducing it to udp only so far. Surely I'll try again (of course not repeating thing that did not work the first time),

Warfley

  • Hero Member
  • *****
  • Posts: 1499
Re: lnet udp how to exit gracefully
« Reply #5 on: May 06, 2023, 11:43:45 pm »
I don't know much about lnet (and just the fact that it simulates connection behavior for a connectionless protocol tells me to better stay away from it), but when dealing with IO you probably also use some form of parallelization. Then you often have the problem that if you free your IO doing component in one event, another event, either in parallel or scheduled afterwards may try to access that memory after it has been freed.
For example if you have one thread listening for messages and another thread performs the closing of the stream and freeing the object directly afterwards, the listening thread will be woken up when the stream is closed, and may want to access the stream object to check what happend, but that stream object might already been destroyed during the time it took the thread to wake up.

So the main question is, in which context are you calling the disconnect and the Destroy? Is your application threaded, if so from what thread is this called, are there other threads that may access the object at the same time?
Also looking at the source of the TLUDPs disconnect method
Code: Pascal  [Select][+][-]
  1.     (*
  2.      * Apply Patch: https://github.com/almindor/lnet/issues/15
  3.      * This Issue is not solved yet.
  4.      * if disconnect is called within a socket event then FRootSock is not allowed to be freed
  5.      * if Disconnect is called outside a socket event then FRootSock needs to be freed otherwise
  6.      *   a memory leack is created.
  7.      *
  8.      * as the normal case is that disconnect is called from outside a socket event
  9.      * the free method is choosen.
  10.      *)
The question is do you call it from within an event handler or from outside?

If you use threading, the quick and dirty solution is usually to just put a sleep(100) or so before the Freeing of the object. A more thourogh way would be to correctly synchronize your threads, but this can be much harder to do properly.

PS: And to say what I always say about this issue, especially if you are new to networking, don't use some high level event based networking libraries for base protocols like raw TCP or UDP. Using the Berkley Sockets API (sockets unit in pascal) is very easy, and you have much more control about when what happens. Only use such libraries when you know very well how they operate, how they use threading and synchronization, etc.
« Last Edit: May 06, 2023, 11:46:08 pm by Warfley »

TRon

  • Hero Member
  • *****
  • Posts: 2537
Re: lnet udp how to exit gracefully
« Reply #6 on: May 07, 2023, 12:20:03 am »
I don't know much about lnet ....
When you are threading or use other complicated constructions then you would not be using the visual components of LNet , rather the non-visual ones. Other than that you don't destroy visual controls manually in a normal situation.

Though it is possible that the form or datamodule the component lives on is destroyed before a form trying to access the component (but then your issue is much bigger in that the form/datamodule is not even valid to access anymore to begin with).

fwiw: the disconnect of the LNet UDP component seems not what you think it means in the sense of normal network used terminology. It seems to act like an internal state to indicate to stop listening (listen) to the socket.

@lado:
In the OPM LNet package is a directory named examples/console/ludp that is using only UDP and that can be adapted to a version that uses the visual TLUDPComponent.
« Last Edit: May 07, 2023, 12:59:27 am by TRon »

lado

  • New Member
  • *
  • Posts: 12
Re: lnet udp how to exit gracefully
« Reply #7 on: May 07, 2023, 10:39:27 am »
Thank you both for helping me.
I dug again into the examples and was able to solve my issues. The solution is to use TLConnection along with TLUDP. Using the TLConnection Disconnect method makes it possible to gracefully exit the application.

 

TinyPortal © 2005-2018