Recent

Author Topic: "Impossible to create epoll, too many open files" error and lNet  (Read 893 times)

washburn_it

  • New Member
  • *
  • Posts: 25
Hi,

some year ago I developed a program to control my fish tank with a Raspberry Pi...it controls water temperature, pH, lights.
Some days ago I implemented also to receive power consumption data of my house from a 2nd Raspberry that is connected to a SDM120C.
Those data are displayed to the "fish tank" Raspberry through a 7" LCD display.
Data are received through a TCP communication (using lNet components) where the 2nd raspberry is the TCP Server and the "fish tank" raspberry is the TCP client, data are shown on request (by clicking on a button on the main Form) where a TTimer is activated and every 10 seconds request data to the TCP server.
The "polling cycle" is the following:

- TCP Client is created
- it connects to the TCP server
- acquires data
- closes the connection
- the "TLTCP" derived object is freed.
- waits 10 seconds and the cycle start again

Now the problem....if I keep the "power" monitoring active, after a certain time the error in the subject appears then I must close the program and open it again or reboot the "fish tank" raspberry.
Trying to find the problem, I launched the command "ls -l /proc/24130/fd" (where "24130" is the PID of the program) after activating "power" monitoring and I found that there are an increasing number of lines "anon_inode:[eventpoll]" that stops only when I stop the TCP connection (thus the "power" monitoring).
This the code of the TCP Client:

Class definition

Code: Pascal  [Select][+][-]
  1. Type
  2.   TPwrThread= class
  3.     private
  4.       IP: string;
  5.       status: string;
  6.       datiStr: string;
  7.       porta: integer;
  8.       FCon : TLTcp; //client TCP
  9.       procedure Scrivi2Log(str: string);
  10.       function GetAppDirec(): string;
  11.       procedure OnDs(aSocket: TLSocket);  //disconnessione dal server
  12.       procedure OnRe(aSocket: TLSocket);  //ricezione da server
  13.       procedure OnEr(const msg: string; aSocket: TLSocket); //errori
  14.       procedure ElaboraDati();
  15.       procedure SetStatus();
  16.     protected
  17.       procedure Run;
  18.     public
  19.       Constructor Create(IPAddr: string; port: integer);
  20.       destructor Destroy; override;
  21.   end;
  22.  
  23.  


Code: Pascal  [Select][+][-]
  1. constructor TPwrThread.Create(IPAddr: string; port: integer);
  2. begin
  3.     //costruttore classe
  4.  
  5.     IP:= IPAddr;
  6.     porta:= port;
  7.  
  8.     //TCP client creation
  9.     FCon := TLTCP.Create(nil);
  10.     FCon.OnError := @OnEr; // assign callbacks
  11.     FCon.OnReceive := @OnRe;
  12.     FCOn.OnDisconnect := @OnDs;
  13.     FCon.Timeout := 100; // responsive enough, but won't hog cpu
  14.  
  15.     //inherited Create(CreateSuspended);
  16. end;
  17.  
  18. destructor TPwrThread.Destroy;
  19. begin
  20.   try
  21.     FCon.Free; // free the connection
  22.   except
  23.     //
  24.   end;
  25.   inherited Destroy;
  26. end;
  27.  
  28. procedure TPwrThread.OnDs(aSocket: TLSocket);
  29. begin
  30.   //Scrivi2Log('Perso connessione a server');
  31.   status:= 'non connesso';
  32.   frmMain.lbTCPSrv.Caption:= status;
  33.   //Synchronize(@SetStatus);
  34.  
  35. end;
  36.  
  37. procedure TPwrThread.OnRe(aSocket: TLSocket);
  38. var
  39.   s: string;
  40. begin
  41.   //ricezione dati da server
  42.   if aSocket.GetMessage(s) > 0 then
  43.   begin
  44.     datiStr:= s;
  45.     //flDati:= true;
  46.   end;
  47.  
  48. end;
  49.  
  50. procedure TPwrThread.OnEr(const msg: string; aSocket: TLSocket);
  51. begin
  52.   //errori vari
  53.   Scrivi2Log(msg); // if error occured, write it
  54.  
  55.   frmMain.lbTCPSrv.Caption:= msg;
  56.   //Synchronize(@SetStatus);
  57.  
  58. end;
  59.  
  60. procedure TPwrThread.Run;
  61. begin
  62.     //esecuzione thread
  63.  
  64.     //connetto al TCP server
  65.     if FCon.Connect(IP, porta) then
  66.     begin
  67.       //attende connessione al TCP server
  68.       repeat
  69.         FCon.CallAction; // wait for "OnConnect"
  70.         Sleep(1);
  71.         Application.ProcessMessages;
  72.       until FCon.Connected;
  73.  
  74.       status:= 'connesso';
  75.       frmMain.lbTCPSrv.Caption:='connesso';
  76.       //Synchronize(@SetStatus);
  77.  
  78.       //invio richiesta dati al TCP server
  79.       datiStr:='';
  80.       FCon.SendMessage('*d');  //sends the data request to the server
  81.       FCon.CallAction; // eventize lNet loop
  82.       //elaboro i dati ricevuti
  83.       ElaboraDati;
  84.     end;
  85.  
  86.     FCon.Disconnect(true);
  87.     FCon.Free;
  88.     //Scrivi2Log('Thread TCP Client terminato');
  89. end;
  90.  
  91.  

Main program timer to read data

Code: Pascal  [Select][+][-]
  1. procedure TfrmMain.tmPwrTimer(Sender: TObject);
  2. begin
  3.     //power data reading
  4.  
  5.     tmPwr.Enabled:= false;
  6.  
  7.     PWR := TPwrThread.Create('192.168.1.122', 5050);
  8.     PWR.Run;
  9.     PWR.Free;
  10.  
  11.     tmPwr.Enabled:= true;
  12. end;
  13.  

Data are reading in the "TPwrThread" class, basically it's a string that contains values as voltage, current, power.
The procedure "ElaboraDati" takes the "data string" received in "OnRe(aSocket: TLSocket)" and assigns each value to some labels to the main Form.
What could be causing that error?
It seems that the socket or the connection is not closed and in some way that allocates "open files" until the limit is reached, then the error.
Thank you

Roberto
« Last Edit: January 06, 2021, 05:12:06 pm by washburn_it »

washburn_it

  • New Member
  • *
  • Posts: 25
Re: "Impossible to create epoll, too many open files" error and INet
« Reply #1 on: January 06, 2021, 05:11:48 pm »
I fixed the problem by myself...the problem was due to how I was using the component, freeing it after every receiving of the data caused the problem.
Now I "encapsulated" it into a thread and it is freed only when the thread is terminated, leaving the connection active for the whole running time of the thread: this fixed the problem.
Regards,


Roberto

MarkMLl

  • Hero Member
  • *****
  • Posts: 2557
Re: "Impossible to create epoll, too many open files" error and INet
« Reply #2 on: January 06, 2021, 05:48:21 pm »
I fixed the problem by myself...the problem was due to how I was using the component, freeing it after every receiving of the data caused the problem.
Now I "encapsulated" it into a thread and it is freed only when the thread is terminated, leaving the connection active for the whole running time of the thread: this fixed the problem.

Sorry, didn't spot that earlier and am not going through your code right now. I had something very similar a few weeks ago where I was neglecting to close a UDP socket... just because it's connectionless doesn't mean that every open doesn't have to be paired with a close.

Not sure if Lnet is suffering from the same problem... I've put work in the past into trying to understand it and concluded it wasn't worth the effort for the things I needed to do.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

washburn_it

  • New Member
  • *
  • Posts: 25
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #3 on: January 06, 2021, 06:11:32 pm »
I didn't try the "UDP" connection but it's supported by LNet, like also http, smtp and ftp protocols.
It was my mistake but it's pretty easy to implement a simple TCP client/server as I was trying to do.
Consider that package in the future if you still have to implement networking functionality to your programs.
Regards,


Roberto

MarkMLl

  • Hero Member
  • *****
  • Posts: 2557
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #4 on: January 06, 2021, 06:21:28 pm »
I didn't try the "UDP" connection but it's supported by LNet, like also http, smtp and ftp protocols.
It was my mistake but it's pretty easy to implement a simple TCP client/server as I was trying to do.
Consider that package in the future if you still have to implement networking functionality to your programs.

I've wasted plenty of time on Lnet in the past, and have very little intention of doing so in the future. It's only marginally supported by its original authors, is vastly overcomplex since by and large it predates threads, and has some very nasty failure behaviour.

As I said in a different thread a few days ago: simple jobs like TCP streams and UDP datagrams can be handled easily enough without a dedicated library, and while its support for Telnet is useful the associated complexity (and nasty failures when one end or the other drops the connection without warning) mean that a rewrite is badly needed.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

washburn_it

  • New Member
  • *
  • Posts: 25
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #5 on: January 06, 2021, 06:31:50 pm »
Thanks for the advice about LNet, I'm using it just since a week and for a "hobbyst" purpose at home.
For my job I use different languages (mainly C#) that already integrates libraries for almost everything.
Regards,


Roberto


MarkMLl

  • Hero Member
  • *****
  • Posts: 2557
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #6 on: January 06, 2021, 06:53:35 pm »
Thanks for the advice about LNet, I'm using it just since a week and for a "hobbyst" purpose at home.
For my job I use different languages (mainly C#) that already integrates libraries for almost everything.

Remember also that there's two variants: the one on Github and the one shipped with FPC (for the use of installation utilities). However I've no particular reason to believe that one of those is substantially more or less reliable than the other.

I got some patches into the latter variant perhaps five years ago to improve the way it handled Telnet subcommands, specifically to support a terminal emulator (i.e. the Telnet client end) that I was attempting to connect to something with slightly quirky Telnet terminal-type handling. I've also used it more recently to implement a Telnet server in a couple of things for debugging purposes... /not/ the sort of thing I'd expect a customer to see.

I've put much more time into trying to debug the Telnet code over the last few months than it would have taken to rewrite it from scratch, or at least get in a good foundation onto which various terminal handlers could be layered.

As far as other libraries go: there's things like Synapse, although in my experience once one starts doing anything that needs a custom protocol (i.e. not HTTP, FTP etc.) one's better off going to the underlying (Berkeley) sockets API.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

MarkMLl

  • Hero Member
  • *****
  • Posts: 2557
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #7 on: April 06, 2021, 11:54:41 am »
I've also used it more recently to implement a Telnet server in a couple of things for debugging purposes... /not/ the sort of thing I'd expect a customer to see.

I've put much more time into trying to debug the Telnet code over the last few months than it would have taken to rewrite it from scratch, or at least get in a good foundation onto which various terminal handlers could be layered.

I've just come across my note regarding the Telnet problem in the variant of Lnet bundled with FPC, I don't know whether it affects the one on Github.

Code: Pascal  [Select][+][-]
  1. (*  * At console, ATTACH: SPO command issued. Port e.g. 5500 now listening.     *)
  2. (*  * First Telnet user attaches to port 5500 successfully.                     *)
  3. (*  * Second user attempts to attach to port 5500, rejected.                    *)
  4. (*  * First user detaches while second user's socket is in TIME_WAIT state.     *)
  5. (*  * There are now two sockets in TIME_WAIT state, which confuses the server.  *)
  6. (*  * No user can attach without a detach/attach at the main console, which     *)
  7. (*    won't work while sockets are in the TIME_WAIT state.                      *)
  8.  

I'll be reimplementing this for my own use at some point, based on a separate thread which splits incoming Telnet traffic into a stream for data and separate FIFOs for commands/results and physical status changes. Any more complex protocols I will obviously be using something like Synapse for, but Telnet is sufficiently useful for programs which aren't primarily network-oriented (and sufficiently neglected by mainstream libraries) to be treated as a special case.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

washburn_it

  • New Member
  • *
  • Posts: 25
Re: "Impossible to create epoll, too many open files" error and lNet
« Reply #8 on: April 06, 2021, 07:09:10 pm »
After some months, some weeks ago, I had to stop using LNet since every now and then the program got "frozen" so I had to close it and launch it again.
At first I thought it was due to the power supply because sometime a yellow "flash" appeared on the screen, then I changed it but the program kept stopping working.
So I recalled your advice about LNet and I tried to disable the thread that was using that component: two weeks have passed without problems.
I permanently cancelled the thread from the source code and the component.
Now data are displayed by an ESP8266 NodeMCU (maybe you know it but, if not, it's a micro equipped with wifi) with a 2.8" LCD.
Regards,


Roberto
« Last Edit: April 06, 2021, 07:12:26 pm by washburn_it »

 

TinyPortal © 2005-2018