Recent

Author Topic: cannot receive messages; udp server with lnet  (Read 13497 times)

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #75 on: July 04, 2022, 11:20:40 pm »
I just try to avoid the main "var" hell that I am getting every time that I start a project.
That's why you can work with procedures and functions.
Look at my last example (added it in an edit) passing sock as function result.
You can put everything in the main loop in a separate procedure main and call it right after the main-begin. Then you have zero global variables.

MarkMLl

  • Hero Member
  • *****
  • Posts: 6676
Re: cannot receive messages; udp server with lnet
« Reply #76 on: July 04, 2022, 11:29:16 pm »
You are (again) correct. The local variable lives for one repeat loop, for loop, even if you copy-paste the lines multiple times, then it zeroes in my pointer test.  %) I just try to avoid the main "var" hell that I am getting every time that I start a project.

I think you need to explain what you mean by 'main "var" hell' in this context.

I think it's worth throwing in here that Pascal's idea of local variables is shared by most languages, so please don't feel that the Pascal language (or the FPC implementation) is being obstructive.

There might possibly be a way to make a local variable externally visible by making it static and returning a pointer, but that would be excruciatingly bad practice so please don't ask me to explain further :-)

Global variables have an undeservedly poor reputation, but that is mainly because novice programmers tend to overuse them. In practical terms, even the Delphi and Lazarus IDEs use them heavily despite there being preferable workarounds.

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

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #77 on: July 05, 2022, 12:08:49 am »
Quote
That's why you can work with procedures and functions.
Look at my last example (added it in an edit) passing sock as function result.
You can put everything in the main loop in a separate procedure main and call it right after the main-begin. Then you have zero global variables.
Very neat example! 8).

And just for the sake of the question:
Code: Pascal  [Select][+][-]
  1. program pointer_test;
  2. uses sysutils, cmem;
  3. var
  4.         p: pointer;
  5.  
  6. procedure a;
  7.  
  8. var
  9.         x:pointer;
  10. begin
  11.         x:=getmem(1);
  12.     integer(x^):=5;
  13.     p:=x;
  14. end;
  15.  
  16. begin
  17.  
  18.         a;
  19.     repeat
  20.         sleep(100);
  21.                 writeln( uint64(p^));
  22.     until false;
  23.         readln;
  24.  
  25. end.

what could possibly go wrong?? :D

Quote
I think you need to explain what you mean by 'main "var" hell' in this context
many vars that are common for procedures/functions.

Quote
I think it's worth throwing in here that Pascal's idea of local variables is shared by most languages, so please don't feel that the Pascal language (or the FPC implementation) is being obstructive.
absolutelly not!

Quote
There might possibly be a way to make a local variable externally visible by making it static and returning a pointer, but that would be excruciatingly bad practice so please don't ask me to explain further :-)

Global variables have an undeservedly poor reputation, but that is mainly because novice programmers tend to overuse them. In practical terms, even the Delphi and Lazarus IDEs use them heavily despite there being preferable workarounds.

I am just exploring possible options.
« Last Edit: July 05, 2022, 12:10:25 am by prodingus »
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #78 on: July 05, 2022, 12:38:22 am »
what could possibly go wrong?? :D
That example should work fine.
That's because you create something in memory and copy the pointer to another pointer.

The first example you had, you had a variable which disapears after the procedure and your pointer is hanging. In this example the pointer still points to some memory thats created and not released. So perfectly fine.

BTW. Your original second example with psock only went wrong because you had a pointer to a pointer of which the first pointer went away after the procedure. If you did a psock := sock it would have worked (that's what i did in my example but as a function result).

You really need to realize that TLUDPL is a class and variables of classes are just pointers to an instance of that class. So sock := TLUDPL.Create will create a pointer to a TLUDPL instance. It's redundant to create a pointer to Sock because Sock is already a pointer. So doing pSock := Sock would have worked because although Sock, as pointer itself, is destroyed, the memory where it points to wasn't released and pSock would have still been valid. But doing pSock := @Sock (which you did) was wrong because that points to a pointer (which is a pointer itself) which will be destroyed after the procedure.

I hope I explained this a bit clearly :)

Eventually you will continue to work more and more with procedures and functions and finally you will also grasp the notion of classes :)

There was a website which goes over the basics of object pascal.
Maybe it's some interesting reading for you.
Modern Object Pascal Introduction for Programmers

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #79 on: July 06, 2022, 08:37:58 pm »
Quote
So sock := TLUDPL.Create will create a pointer to a TLUDPL instance.
Interesting! I never thougt of it as pointer.

Quote
I hope I explained this a bit clearly

Yes, very clearly, but one small issue..
psock:=sock; does not work because sock is acting as a normal variable. Even casting it as pointer, psock:=pointer(sock); is not working.. Do I miss something here?

lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #80 on: July 06, 2022, 08:39:53 pm »
psock:=sock; does not work because sock is acting as a normal variable. Even casting it as pointer, psock:=pointer(sock); is not working.. Do I miss something here?
What type is psock?
If you make psock of type TLUDP (because TLUDP is a pointer by itself) it will work fine.

You don't want a pointer to a TLUDP because that's just silly. It has no advantages.

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #81 on: July 06, 2022, 08:47:48 pm »
Yes! psock was ^tludp (because I though of it is as variable.)

Changing from the previous multi_1 just for the sake of the discussion:
Code: Pascal  [Select][+][-]
  1. program multi_1;
  2. uses
  3.         SysUtils, crt, lnet; //, lnetbase
  4. var
  5.  
  6.         tmp: string;
  7.         psock:TLUDP;
  8.  
  9. procedure connect(port:integer);
  10. var
  11.         Sock: TLUDP;
  12. begin
  13.  
  14.         Sock := TLUdp.Create(nil);
  15.     psock:=sock;
  16.     Sock.listen(port);
  17.  
  18. end;
  19.  
  20.  
  21. begin
  22.  
  23.     connect(1234);
  24.  
  25.         repeat
  26.         pSock.CallAction;
  27.         pSock.GetMessage(tmp);
  28.         writeln(tmp + ' ' + pSock.host);
  29.         sleep(500);
  30.         until False;
  31. end.

It works! Needless to say thanks again for the insights!
« Last Edit: July 06, 2022, 08:58:17 pm by prodingus »
lazarus 2.2.0, FPC 3.2.2

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #82 on: July 07, 2022, 11:18:47 pm »
@Warfley,

I just tried to use your unit. It does not compile on my setup (lazarus 1.6, FPC 3.0, SVN 51630), I get various errors, unless there is something wrong in my configurations. I have no time to "upgrade" my lazarus build, so I won't be able to share any experience.

@rvk,
Before trying your other examples, is it possible to get the host (sender) address on the last example I posted?
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #83 on: July 07, 2022, 11:46:57 pm »
@rvk,
Before trying your other examples, is it possible to get the host (sender) address on the last example I posted?
Yes, it's the same as in the example I posted here
https://forum.lazarus.freepascal.org/index.php/topic,59777.msg446588.html#msg446588

You already have it there in your writeln as pSock.host.

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #84 on: July 07, 2022, 11:59:54 pm »
it's not working.
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #85 on: July 08, 2022, 12:36:23 am »
it's not working.
Ok. I'm not sure if it works with just the getmessage.

It was working with the onreceive event with the aSocket parameter.

Like this
Code: Pascal  [Select][+][-]
  1. program project1;
  2. {$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
  3. {$APPTYPE CONSOLE}
  4. uses
  5.   SysUtils, crt, lnet, lnetbase;
  6. var
  7.   Sock: TLUDP;
  8.   tmp: string;
  9.  
  10. type
  11.   TMyDummy = class
  12.     class procedure OnReceive(aSocket: TLSocket);
  13.   end;
  14.  
  15. class procedure TMyDummy.OnReceive(aSocket: TLSocket);
  16. begin
  17.   if Sock.GetMessage(tmp) > 0 then
  18.     writeln(tmp + ' from ' + aSocket.PeerAddress);
  19. end;
  20.  
  21. begin
  22.   Sock := TLUdp.Create(nil);
  23.   Sock.OnReceive := TMyDummy.OnReceive;
  24.   Sock.listen(1234);
  25.   repeat
  26.     Sock.CallAction;
  27.     sleep(100);
  28.   until False;
  29. end.

I'm not sure if it's possible without the event.
I can't check that at the moment.
Maybe tomorrow.

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #86 on: July 08, 2022, 12:35:17 pm »
You need to access the TLSocket to get to the host-name of the sender.

TLUDPL van handle multiple connections.
Normally the correct TLSocket is passed to the OnReceive function.
But because you are just calling GetMessage outright... you don't know which connection it is.

If you only have one connection you can use the following line (just taking the first TLSocket in TUDPL):
Code: Pascal  [Select][+][-]
  1.     writeln(tmp + ' ' + Sock.Socks[0].PeerAddress);

But if you have multiple connection this gets problematic.
In that case you definitely need to go with my other example implementing the OnReceive event.

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #87 on: July 08, 2022, 07:39:46 pm »
Amen man, it works!!! ;D

However I got into two problems:
Code: Pascal  [Select][+][-]
  1. program multi_3;
  2. uses
  3.         winsock, SysUtils, lnet, crt, Classes, StreamIO, Windows, strutils;
  4. var
  5.         buff: string;
  6.     psock:TLUDP;
  7.     psock2:TLUDP;       //tludp is pointer type by itself
  8.     i: integer= 0;
  9.     j: integer= 0;
  10.     k: integer= 0;
  11.     myip: string;
  12.     msg: string;
  13.  
  14. type
  15.         TConsoleOutputStream = class(TStream)
  16.     function Write(const Buffer; Count: longint): longint; override;
  17. end;
  18.  
  19. function TConsoleOutputStream.Write(const Buffer; Count: longint): longint;
  20. var
  21.     charcount: longword=0;
  22. begin
  23.     WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), @Buffer, Count, charcount, nil);
  24.     Result := charcount;
  25. end;
  26.  
  27. function getlocalip:string;
  28. type
  29.   pu_long = ^u_long;
  30. var
  31.   varTWSAData : TWSAData;
  32.   varPHostEnt : PHostEnt;
  33.   varTInAddr : TInAddr;
  34.   namebuf : Array[0..255] of char;
  35. begin
  36.   If WSAStartup($101,varTWSAData) <> 0 Then
  37.   Result := 'No. IP Address'
  38.   Else Begin
  39.     gethostname(namebuf,sizeof(namebuf));
  40.     varPHostEnt := gethostbyname(namebuf);
  41.     varTInAddr.S_addr := u_long(pu_long(varPHostEnt^.h_addr_list^)^);
  42.     Result := inet_ntoa(varTInAddr);
  43.   End;
  44.   WSACleanup;
  45. end;
  46.  
  47.  
  48. procedure connectr(port:integer);
  49. var
  50.         Sock: TLUDP;
  51. begin
  52.         Sock := TLUdp.Create(nil);
  53.     psock:= sock;
  54.     Sock.listen(port);
  55. end;
  56.  
  57. procedure connects(addr:string; port:integer);
  58. var
  59.         Sock2: TLUDP;
  60. begin
  61.         Sock2 := TLUdp.Create(nil);
  62.     psock2:= sock2;
  63.     Sock2.connect(addr, port);
  64. end;
  65.  
  66.  
  67. begin
  68.         AssignStream(Output, TConsoleOutputStream.Create);
  69.         Rewrite(Output);
  70.     crt.WindMaxY := 9999;
  71.     myip:= getlocalip;
  72.     i:=0;
  73.     writeln('ip: ',myip);
  74.         write('send or listen?');
  75.         readln(k);
  76.  
  77.     if k=1 then begin
  78.         connects('1.1.1.10', 1234);
  79.         msg:='ping';
  80.         psock2.sendmessage(msg);
  81.     end;
  82.  
  83.     begin
  84.         connectr(1234);
  85.                 repeat
  86.                 pSock.CallAction;
  87.                 pSock.GetMessage(buff);
  88.             if buff <> '' then begin
  89.                 if {(i mod 100 = 0)} true then writeln(buff,' ',pSock.Socks[0].PeerAddress);
  90.  
  91.                         connects(pSock.Socks[0].PeerAddress, 1234);
  92.                     inc(i);
  93.                                 msg:=inttostr(i);
  94.                                 psock2.sendmessage(msg);
  95.                     buff:='';
  96.             end;
  97.                 delay(0);
  98.                 until keypressed=true;
  99.     end;
  100.  
  101.     readln;
  102. end.

The first is the program hangs when it sends 16381 messages (I'm sure that number is not "random").
The second and most ridiculous: sleep(1) cause the program to run extremelly slow, almost no CPU utilization, whereas no sleep at all uses 100% the cpu (even with less screen updates).
« Last Edit: July 08, 2022, 07:42:02 pm by prodingus »
lazarus 2.2.0, FPC 3.2.2

rvk

  • Hero Member
  • *****
  • Posts: 6111
Re: cannot receive messages; udp server with lnet
« Reply #88 on: July 08, 2022, 08:12:51 pm »
Your first problem....
You do a connects(pSock.Socks[0].PeerAddress, 1234); EACH time you get a message.
But you don't close that connection.
So you end up with A LOT of connections.
You need to free psock after you send a message otherwise you end up with lots of TLUDPs in memory which you can't even use because pointer psock keeps getting overwritten.

Try to put a psock.free at the end of the if buf <> '' block.
(Best would be to use a try/finally structure but maybe that's for later.)

Your second problem...
Of course you have 100% cpu if you do sleep(1) or no sleep. What did you expect. Your program doesn't pause so it takes all the cpu. That's logical.

prodingus

  • Jr. Member
  • **
  • Posts: 83
Re: cannot receive messages; udp server with lnet
« Reply #89 on: July 08, 2022, 08:24:01 pm »
With sleep(1) the program acts like having sleep(500) for example
lazarus 2.2.0, FPC 3.2.2

 

TinyPortal © 2005-2018