Lazarus

Programming => Networking and Web Programming => Topic started by: prodingus on July 01, 2022, 01:04:42 am

Title: cannot receive messages; udp server with lnet
Post by: prodingus on July 01, 2022, 01:04:42 am
Hi!

the client works just fine:

Code: Pascal  [Select][+][-]
  1. program test1;
  2. {$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
  3. {$APPTYPE CONSOLE}
  4. uses
  5.         sysutils, crt, lnet;
  6. var
  7.         Sock:TLUDP;
  8. begin
  9.        
  10.     Sock:= TLUdp.Create(nil);
  11.     Sock.connect('1.1.1.2', 28);
  12.  
  13.     repeat
  14.     Sock.sendmessage('ghj');
  15.     until false;
  16.  
  17.  
  18. end.

on the "server" I use the hercules utility to see the data (and I see them just fine).

However, when using this code to make my version of server:

Code: Pascal  [Select][+][-]
  1. program test1;
  2. {$IFDEF FPC}{$MODE DELPHI}{$ENDIF}
  3. {$APPTYPE CONSOLE}
  4. uses
  5.         sysutils, crt, lnet;
  6. var
  7.         Sock:TLUDP;
  8.         tmp: string;
  9. begin
  10.        
  11.         Sock:= TLUdp.Create(nil);
  12.     //Sock.connect('1.1.1.2', 28);
  13.         Sock.listen(word('28'));
  14.  
  15.     repeat begin
  16.     Sock.getmessage(tmp);
  17.     writeln(Sock.getmessage(tmp));
  18.  
  19.     sleep(100);
  20.     end; until false;
  21.  
  22.  
  23. end.

I get nothing. Can anyone provide a barebone "get udp message loop" example without classes, methods  and stuff?
Title: Re: cannot receive messages; udp server with lnet
Post by: dje on July 01, 2022, 01:38:38 am
What is up wth this line?
Code: Pascal  [Select][+][-]
  1. Sock.listen(word('28'));

Check the examples folder for lnet. There is an example called: packages/lnet/examples/console/ludp/ludp.pp
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 01, 2022, 01:46:11 am
I did. The "word('28')" works only that way as it throws "constant string", expected "word".
Title: Re: cannot receive messages; udp server with lnet
Post by: dje on July 01, 2022, 01:56:37 am
Why not just put 28?
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 01, 2022, 02:01:32 am
Stupid me, just 28 works! Still no received data from "server".
Title: Re: cannot receive messages; udp server with lnet
Post by: dje on July 01, 2022, 03:22:23 am
The ludp example works fine. Your code fails here for a few reasons. The port number 28 returns Permission denied. I used 1234 with ludp and it worked.

Also, the example uses the callback OnReceive to handle listening events.

As a tip. Always start with a working example and then hack it to suit your requirements.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 01, 2022, 09:19:49 am
Stupid me, just 28 works! Still no received data from "server".

Look, if you'd told us in the first place what OS, version of the compiler etc. you'd got you'd have made it a damn sight easier for everybody.

You can't use ports <1024 (or maybe <=, can't remember) on a unix-like OS including Linux without having root privilege. Not sure whether there's a corresponding restriction on Windows etc.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 01, 2022, 04:53:00 pm
Sorry for the missing info: the testing is done on 2 win7 sp1 x64 lite vms, lazarus 1.6, FPC 3.0, SVN 51630.

Quote
Your code fails here for a few reasons. The port number 28 returns Permission denied. I used 1234 with ludp and it worked.

Before switching to lnet, I was testing with BlckSock (synapse?). I was still using port 28 on both vms and it I was sending and receiving just fine.

Quote
Also, the example uses the callback OnReceive to handle listening events.
I don't work with classes and methods... I don't know how to use it.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 01, 2022, 04:56:46 pm
Ps, changing port number, still no receive.
Title: Re: cannot receive messages; udp server with lnet
Post by: Remy Lebeau on July 01, 2022, 07:22:43 pm
Code: Pascal  [Select][+][-]
  1. repeat begin
  2.   Sock.getmessage(tmp);
  3.   writeln(Sock.getmessage(tmp));
  4.  
  5.   sleep(100);
  6. end; until false;

Why are you calling getmessage() twice per loop iteration?  Get rid of the 1st one.  Or, use the OnReceive event, like Derek suggested.

You can't use ports <1024 (or maybe <=, can't remember) on a unix-like OS including Linux without having root privilege. Not sure whether there's a corresponding restriction on Windows etc.

There is no such restriction on Windows.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 03:00:45 pm
Quote
Why are you calling getmessage() twice per loop iteration?  Get rid of the 1st one.

I did try with one,  same result as before.

Quote
Or, use the OnReceive event, like Derek suggested.

Can someone help me on this? I need a straigthforward way (if possible) to receive udp data.
Title: Re: cannot receive messages; udp server with lnet
Post by: dje on July 02, 2022, 04:15:08 pm
I don't work with classes and methods... I don't know how to use it.
Can someone help me on this? I need a straigthforward way (if possible) to receive udp data.

We can go around and around in circles for days. You cant blindly brute force an API to work the way you want. There are standard processes required to work though these problems. The first... Is to verify that the example is working.

1) Have you successfully compiled and tested the example? If yes...
2) Do you understand the example? If no, then play with the code and read the LNet classes until you do, then goto (2)
3) If yes, split the example into two separate projects for client/server.
4) If your hacking fails, return to step 2

It looks like you want the API to match your desired "style of coding" rather than accept the API must be used in a certain way.

Personally, I use Indy since I've been using that for almost 20 years. But, I can tell you, LNet is not a low Unix networking API.

Follow the example!
Title: Re: cannot receive messages; udp server with lnet
Post by: dje on July 02, 2022, 04:26:54 pm
One last thought. RE: I don't work with classes and methods... I don't know how to use it.

You don't have to use a OOP class libraries. I know lots of coders who refuse to use them for a number of reasons.

There is nothing wrong with going "old school". Here is C code for UDP client/servers.

https://www.cs.cmu.edu/afs/cs/academic/class/15213-f99/www/class26/

You can convert that to Pascal, or go with C. It doesn't matter. But, really, if you don't want learn Object Pascal, then why are you asking for help?
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 04:36:06 pm
Quote
if you don't want learn Object Pascal, then why are you asking for help?

Is it wrong to use plain Pascal instead of Object Pascal?

As I created a simple loop that sends udp packets (and I receive them on the "server" side using the hercules utility), I need a simple loop that "gets" any pressent packets.
Title: Re: cannot receive messages; udp server with lnet
Post by: PascalDragon on July 02, 2022, 04:38:05 pm
Quote
if you don't want learn Object Pascal, then why are you asking for help?

Is it wrong to use plain Pascal instead of Object Pascal?

Considering that you're using lnet you are using Object Pascal. So if you want to use the components correctly you must use the mechanisms and concepts provided by Object Pascal (which includes event handlers).
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 04:40:22 pm
Quote
Considering that you're using lnet you are using Object Pascal. So if you want to use the components correctly you must use the mechanisms and concepts provided by Object Pascal (which includes event handlers).

Can these handlers be used in my example without creating classes?
Title: Re: cannot receive messages; udp server with lnet
Post by: PascalDragon on July 02, 2022, 04:42:31 pm
Quote
Considering that you're using lnet you are using Object Pascal. So if you want to use the components correctly you must use the mechanisms and concepts provided by Object Pascal (which includes event handlers).

Can these handlers be used in my example without creating classes?

With the development version of FPC (3.3.1) you could use anonymous functions for that, but otherwise and without opening a rabbit hole that might lead to suffering and pain in the future: no.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 05:11:17 pm
Before switching to lnet, I was testing with BlckSock (synapse?).
So why did you want to switch to LNet?

Can these handlers be used in my example without creating classes?
You can try to use a simple class with class function which handles your data. Then you wouldn't need to create an instance but can use the @TDummy.MyReceive() function directly. Not sure if that would work. I prefer Synapse
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 05:49:47 pm
Quote
So why did you want to switch to LNet?
I read that lnet was asynchronus, thats why.

After reading the comments on this thread, it seems lnet is no-go for me. Shall I start a new thread about sockets?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 06:05:31 pm
Quote
So why did you want to switch to LNet?
I read that lnet was asynchronus, thats why.
If you want asynchronous reading of sockets you will always end up with classes and/or threads. That would also be the case for Synapse because it by itself is 'blocking' (the class is even called TBlockSocket in Synapse). You can make your it asynchronous by using it in threads.

But if you want everything in your main procedure and don't want to work with classes and/or threads, you WANT to have blocking reading. So you need to think about what you want first.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 02, 2022, 07:05:49 pm
The easiest way to receive data via UDP is simply using the base socket unit which is provided by the fpc without any additional packages:
Code: Pascal  [Select][+][-]
  1. uses
  2.   sockets;
  3.  
  4. const
  5.   UDPPackLen = 512;
  6. var
  7.   sock: Tsocket;
  8.   buff: Array[0..UDPPackLen-1] of Byte;
  9.   ServerAddr, FromAddr: sockaddr_in;
  10.   FromAddrLen: Integer;
  11.   ClientAddr: String;
  12.   ClientPort: Word;
  13.   MessageSize: SizeInt;
  14. begin
  15.   // Start UDP Server
  16.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  17.   ServerAddr.sin_family:= AF_INET;
  18.   ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  19.   ServerAddr.sin_port := 531; // server port
  20.   fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  21.   // Receive Data
  22.   MessageSize := fprecvfrom(sock, @buff, SizeOf(buff), 0, @FromAddr, @FromAddrLen);
  23.   ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  24.   ClientPort := NToHs(FromAddr.sin_port);
  25. end.

Quote
So why did you want to switch to LNet?
I read that lnet was asynchronus, thats why.

After reading the comments on this thread, it seems lnet is no-go for me. Shall I start a new thread about sockets?
Use select on the socket to check if there is any data. But true asynchronous execution requires your application to be built around that. It's not something you can just "toogle on" using a library. Either you have threads that fire events or you use something like AsyncNet (https://github.com/Warfley/AsyncNet/) which builds on STAX (https://github.com/Warfley/STAX/tree/master/src)
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 02, 2022, 07:27:50 pm
The easiest way to receive data via UDP is simply using the base socket unit which is provided by the fpc without any additional packages:

I agree. And I'm afraid that my opinion of LNet is that it's a can of worms: I've come across various pathological behaviour particularly when one end or the other of a (TCP) connection dropps unexpectedly and the convoluted nature of its code- which attempts to simulate asynchronous operation without doing it "properly" using threads- makes maintenance "tricky".

The variant of LNet bundled with FPC has a bit of extra Telnet handling that isn't in the one on Github, which makes it useful for writing a debugging backdoor for daemon programs (I stress that this should only be used locally because of Telnet's lack of encryption) or a console handler for e.g. a mainframe emulator. But if I needed that functionality for something going into the field I'd redo it from scratch.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 08:12:25 pm
Quote
The easiest way to receive data via UDP is simply using the base socket unit which is provided by the fpc without any additional packages

That's why I started a new thread.

Code: Pascal  [Select][+][-]
  1. uses
  2.   sockets;
  3.  
  4. const
  5.   UDPPackLen = 512;
  6. var
  7.   sock: Tsocket;
  8.   buff: Array[0..UDPPackLen-1] of Byte;
  9.   ServerAddr, FromAddr: sockaddr_in;
  10.   FromAddrLen: Integer;
  11.   ClientAddr: String;
  12.   ClientPort: Word;
  13.   MessageSize: SizeInt;
  14. begin
  15.   // Start UDP Server
  16.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  17.   ServerAddr.sin_family:= AF_INET;
  18.   ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  19.   ServerAddr.sin_port := 531; // server port
  20.   fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  21.   // Receive Data
  22.   MessageSize := fprecvfrom(sock, @buff, SizeOf(buff), 0, @FromAddr, @FromAddrLen);
  23.   ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  24.   ClientPort := NToHs(FromAddr.sin_port);
  25. end.

How to writeln the buff??
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 02, 2022, 08:22:27 pm
Put it into a string, set the length, and then proceed in the usual fashion.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 08:43:41 pm
Code: Pascal  [Select][+][-]
  1. program sockets_1;
  2.  
  3. uses
  4.         sysutils, crt, sockets;
  5.  
  6. const
  7.   UDPPackLen = 512;
  8. var
  9.   sock: Tsocket;
  10.   buff: Array[0..UDPPackLen-1] of Byte;
  11.  
  12.   outp:string;
  13.  
  14.   ServerAddr, FromAddr: sockaddr_in;
  15.   FromAddrLen: Integer;
  16.   ClientAddr: String;
  17.   ClientPort: Word;
  18.   MessageSize: SizeInt;
  19. begin
  20.   // Start UDP Server
  21.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  22.   ServerAddr.sin_family:= AF_INET;
  23.   ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  24.   ServerAddr.sin_port := 1234; // server port
  25.   fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  26.   // Receive Data
  27.   repeat begin
  28.   MessageSize := fprecvfrom(sock, @buff, SizeOf(buff), 0, @FromAddr, @FromAddrLen);
  29.   ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  30.   ClientPort := NToHs(FromAddr.sin_port);
  31.  
  32.   SetString(outp, PAnsiChar(@buff[0]), 3);
  33.   writeln(outp);
  34.   sleep(100);
  35.   end; until false
  36. end.
  37.  

Unless I am wrong, this is not working. Hercules is receiveing, but this is not.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 09:38:36 pm
You're binding your listener to 1.1.1.2? Is that the real addres??
Do you want broadcasts UDP or directed UDP? (also show some code of the server)

You have very little error checking in your code.

For example.
After
Code: Pascal  [Select][+][-]
  1. sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
you could set an
Code: Pascal  [Select][+][-]
  1. assert(sock <> -1);
to check if the sock is really assigned.
(you won't get an error otherwise and nothing will work)

For the loop you should do:
Code: Pascal  [Select][+][-]
  1. if fpbind(.........) = 0 then
  2. begin
  3.   repeat
  4.   until
  5. end
  6. else
  7. begin
  8.   writeln(socketError);
  9. end;
The socketError will give you more information when your fpbind() fails.

Also... change
Code: Pascal  [Select][+][-]
  1. MessageSize := fprecvfrom(.......)
to
Code: Pascal  [Select][+][-]
  1. MessageSize := fprecvfrom(.......)
  2. if MessageSize = -1 then writeln(socketError);

That will also give you a lot more information.

You have port 1234. I do think you need to use htons(1234) but I'm not sure (and you would need to do that also on the server side).
(I'm not that familiar with fpsock)

You also haven't shown anything on the server side and specified anything about the network IP's.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 02, 2022, 09:43:14 pm
Not working /how/? What's going wrong? the fpBind() or the receive? What's in SocketError?

The rather hackish way I'd do it would be something like

Code: Pascal  [Select][+][-]
  1.     uses
  2.       sockets;
  3.      
  4.     const
  5.       UDPPackLen = 512;
  6.  
  7.     var
  8.       sock: Tsocket;
  9.       buff: AnsiString;
  10.       ServerAddr, FromAddr: sockaddr_in;
  11.       FromAddrLen: Integer;
  12.       ClientAddr: String;
  13.       ClientPort: Word;
  14.       MessageSize: SizeInt;
  15.     begin
  16.       // Start UDP Server
  17.       sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  18.       ServerAddr.sin_family:= AF_INET;
  19.       ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  20.       ServerAddr.sin_port := 531; // server port
  21.       fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  22.       // Receive Data
  23.       SetLength(buff, UDPPackLen);
  24.       MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  25.       SetLength(buff, MessageSize);
  26.       ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  27.       ClientPort := NToHs(FromAddr.sin_port);
  28.       WriteLn(buff)
  29.     end.
  30.  

Note that that's untested, I'm in the middle of doing my year-end books /and/ my usual development system has blown up. But it has the advantage that you can see exactly what's in the string using e.g. the Lazarus debugger, noting of course that element

(Modified to emphasise that the buffer should be an AnsiString, i.e. one byte pre character)

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 02, 2022, 10:20:15 pm
I got really bored and wrote a small wrapper around the sockets API that makes it easier to use and less C-ish: https://github.com/Warfley/PasSimpleSockets/tree/master
Just this one Unit:
Code: Pascal  [Select][+][-]
  1. unit SimpleSockets;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   SysUtils, Sockets, {$IfDef WINDOWS}WinSock2{$Else}BaseUnix{$EndIf};
  9.  
  10. type
  11.  
  12.   { Basic Socket Types }
  13.  
  14.   TSocketFD = Sockets.Tsocket;
  15.   TSocketType = (stIPv4, stIPv6, stDualStack);
  16.   TSocket = record
  17.     FD: TSocketFD;
  18.     SocketType: TSocketType;
  19.   end;
  20.  
  21.   TAddressType = (atIN4, atIN6);
  22.   TNetworkAddress = record
  23.     Address: String;
  24.     AddressType: TAddressType;
  25.   end;
  26.  
  27.   { UDP Return Types }
  28.  
  29.   TUDPResult= record
  30.     FromAddr: TNetworkAddress;
  31.     FromPort: Word;
  32.     DataSize: SizeInt;
  33.   end;
  34.  
  35.   generic TUDPDataMessage<T> = record
  36.     FromAddr: TNetworkAddress;
  37.     FromPort: Word;
  38.     Data: T;
  39.   end;
  40.  
  41.   TUDPStringMessage = specialize TUDPDataMessage<String>;
  42.  
  43.   { Exceptions }
  44.  
  45.   EDualStackNotSupported = class(Exception);
  46.   EUnsupportedAddress = class(Exception);
  47.  
  48.   { ESocketError }
  49.  
  50.   ESocketError = class(Exception)
  51.   private
  52.     FCode: Integer;
  53.   public
  54.     constructor Create(ACode: Integer; const FunName: String);
  55.  
  56.     property Code: Integer read FCode;
  57.   end;
  58.  
  59.   EConnectionClosedException = class(Exception);
  60.   EUDPFragmentationException = class(Exception);
  61.  
  62. const
  63.   MaxUDPPackageSize = 512;
  64.  
  65.   { Address Management }
  66.  
  67. function IN4Address(const Address: String): TNetworkAddress; inline;
  68. function IN6Address(const Address: String): TNetworkAddress; inline;
  69. function IN4MappedIN6Address(const In4Address: String): TNetworkAddress; inline;
  70. function INAddr(const Address: String): TNetworkAddress; inline;
  71.  
  72. function IsIPv4Mapped(const IPv6Addr: TNetworkAddress): Boolean; inline;
  73. function ExtractIPv4Address(const IPv6Addr: TNetworkAddress): TNetworkAddress; inline;
  74.  
  75. function IN6Equal(const A, B: String): Boolean;
  76. operator =(const A, B: TNetworkAddress): Boolean; inline;
  77. operator :=(const AStr: String): TNetworkAddress; inline;
  78.  
  79.   { Socket Functions }
  80.  
  81. function TCPSocket(AType: TSocketType): TSocket; inline;
  82. function UDPSocket(AType: TSocketType): TSocket; inline;
  83.  
  84. procedure CloseSocket(const ASocket: TSocket); inline;
  85.  
  86. procedure Bind(const ASocket: TSocket; const AAddress: TNetworkAddress; APort: Word);
  87. procedure TCPServerListen(const ASocket: TSocket; Backlog: Integer); inline;
  88.  
  89. function TCPReceive(const ASocket: TSocket; ABuffer: Pointer; MaxSize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  90. function UDPReceive(const ASocket: TSocket; ABuffer: Pointer; MaxSize: SizeInt; AFlags: Integer = 0): TUDPResult;
  91. function TCPSend(const ASocket: TSocket; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  92. function UDPSend(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress;
  93.                   ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer = 0): SizeInt; inline;
  94.  
  95. function TCPReceiveStr(const ASocket: TSocket; MaxLength: SizeInt; AFlags: Integer = 0): String; inline;
  96. function UDPReceiveStr(const ASocket: TSocket; MaxLength: SizeInt = MaxUDPPackageSize; AFlags: Integer = 0): TUDPStringMessage; inline;
  97. function TCPSendStr(const ASocket: TSocket; const AData: String; AFlags: Integer = 0): SizeInt; inline;
  98. function UDPSendStr(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: String; AFlags: Integer = 0): SizeInt; inline;
  99.  
  100. generic function TCPReceive<T>(const ASocket: TSocket; AFlags: Integer = 0): T; inline;
  101. generic function UDPReceive<T>(const ASocket: TSocket; AFlags: Integer = 0): specialize TUDPDataMessage<T>; inline;
  102. generic function TCPSend<T>(const ASocket: TSocket; constref AData: T; AFlags: Integer = 0): SizeInt; inline;
  103. generic function UDPSend<T>(const ASocket: TSocket; constref ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: T; AFlags: Integer = 0): SizeInt; inline;
  104.  
  105. generic function TCPReceiveArray<T>(const ASocket: TSocket; MaxCount: SizeInt; AFlags: Integer = 0): specialize TArray<T>; inline;
  106. generic function UDPReceiveArray<T>(const ASocket: TSocket; MaxCount: SizeInt; AFlags: Integer = 0): specialize TUDPDataMessage<specialize TArray<T>>; inline;
  107. generic function TCPSendArray<T>(const ASocket: TSocket; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt; inline;
  108. generic function UDPSendArray<T>(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt; inline;
  109.  
  110. // Timeout in MS
  111. function DataPending(const ASocket: TSocket; TimeOut: Integer = 0): Boolean;
  112.  
  113. { Helper }
  114. // Must be in interface because of generic functions
  115.  
  116. type
  117.   _PAddressUnion = ^_TAddressUnion;
  118.   _TAddressUnion = record
  119.   case Boolean of
  120.   True: (In4Addr: Sockets.sockaddr_in);
  121.   False: (In6Addr: Sockets.sockaddr_in6);
  122.   end;
  123.  
  124. procedure FillAddr(AAddress: TNetworkAddress; APort: Word; Addr: _PAddressUnion; DualStack: Boolean); inline;
  125. procedure ReadAddr(Addr: _PAddressUnion; DualStack: Boolean; out AAddress: TNetworkAddress; out APort: Word);
  126. implementation
  127.  
  128. const
  129.   IPPROTO_IPV6 = {$IfDef WINDOWS}41{$Else}41{$EndIf};
  130.   IPV6_V6ONLY = {$IfDef WINDOWS}27{$Else}26{$EndIf};
  131.  
  132. procedure FillAddr(AAddress: TNetworkAddress; APort: Word;
  133.   Addr: _PAddressUnion; DualStack: Boolean);
  134. begin
  135.   if (AAddress.AddressType = atIN4) and DualStack then
  136.     AAddress := IN4MappedIN6Address(AAddress.Address);
  137.   if AAddress.AddressType = atIN4 then
  138.   begin
  139.     Addr^.In4Addr.sin_family := AF_INET;
  140.     Addr^.In4Addr.sin_port := HToNS(APort);
  141.     Addr^.In4Addr.sin_addr.s_addr := LongWord(StrToNetAddr(AAddress.Address));
  142.   end
  143.   else if AAddress.AddressType = atIN6 then
  144.   begin
  145.     Addr^.In6Addr.sin6_family := AF_INET6;
  146.     Addr^.In6Addr.sin6_port := HToNS(APort);
  147.     Addr^.In6Addr.sin6_addr := StrToHostAddr6(AAddress.Address);
  148.     Addr^.In6Addr.sin6_flowinfo := 0;
  149.     Addr^.In6Addr.sin6_scope_id := 0;
  150.   end
  151.   else
  152.     raise EUnsupportedAddress.Create('Address type ' + ord(AAddress.AddressType).ToString + ' not supported');
  153. end;
  154.  
  155. procedure ReadAddr(Addr: _PAddressUnion; DualStack: Boolean; out
  156.   AAddress: TNetworkAddress; out APort: Word);
  157. begin
  158.   if Addr^.In4Addr.sin_family = AF_INET then
  159.   begin
  160.     AAddress := IN4Address(NetAddrToStr(Addr^.In4Addr.sin_addr));
  161.     APort := NToHs(Addr^.In4Addr.sin_port);
  162.   end
  163.   else if Addr^.In6Addr.sin6_family = AF_INET6 then
  164.   begin
  165.     AAddress := IN6Address(HostAddrToStr6(Addr^.In6Addr.sin6_addr));
  166.     if DualStack and IsIPv4Mapped(AAddress.Address) then
  167.       AAddress := ExtractIPv4Address(AAddress);
  168.     APort := NToHs(Addr^.In6Addr.sin6_port);
  169.   end
  170.   else
  171.     raise EUnsupportedAddress.Create('Address Family ' + Addr^.In4Addr.sin_family.ToString + ' not supported');
  172. end;
  173.  
  174. function SocketInvalid(ASocket: TSocketFD): Boolean; inline;
  175. begin
  176.   {$IfDef Windows}
  177.   Result := ASocket = TSocketFD(INVALID_SOCKET);
  178.   {$Else}
  179.   Result := ASocket < 0;
  180.   {$EndIf}
  181. end;
  182.  
  183. function CreateSocketFD(ADomain: TSocketType; AType: Integer; AProto: Integer): TSocketFD;
  184. var
  185.   AFam, v6Only: Integer;
  186. begin
  187.   if ADomain = stIPv4 then
  188.     AFam := AF_INET
  189.   else
  190.     AFam := AF_INET6;
  191.   Result := fpsocket(AFam, AType, AProto);
  192.   if SocketInvalid(Result) then
  193.     raise ESocketError.Create(socketerror, 'socket');
  194.  
  195.   if ADomain = stDualStack then
  196.   begin
  197.     v6Only := 0;
  198.     if fpsetsockopt(Result, IPPROTO_IPV6, IPV6_V6ONLY, @v6Only, SizeOf(v6Only)) <> 0 then
  199.       raise EDualStackNotSupported.Create('Dualstack option not supported on this system: ' + socketerror.ToString);
  200.   end;
  201. end;
  202.  
  203. function IN4Address(const Address: String): TNetworkAddress;
  204. begin
  205.  Result := Default(TNetworkAddress);
  206.  Result.Address := Address;
  207.  Result.AddressType := atIN4;
  208. end;
  209.  
  210. function IN6Address(const Address: String): TNetworkAddress;
  211. begin
  212.  Result := Default(TNetworkAddress);
  213.  Result.Address := Address;
  214.  Result.AddressType := atIN6;
  215. end;
  216.  
  217. function IN4MappedIN6Address(const In4Address: String): TNetworkAddress;
  218. var
  219.   InAddr: TIn_addr;
  220. begin
  221.   InAddr := StrToNetAddr(In4Address);
  222.   Result := IN6Address('::FFFF:%x:%x'.Format([(InAddr.s_bytes[1] shl 8) or InAddr.s_bytes[2],
  223.                                               (InAddr.s_bytes[3] shl 8) or InAddr.s_bytes[4]]));
  224. end;
  225.  
  226. function INAddr(const Address: String): TNetworkAddress;
  227. begin
  228.  Result := Default(TNetworkAddress);
  229.   if Pos(':', Address) = 0 then
  230.     Result.AddressType := atIN4
  231.   else
  232.     Result.AddressType := atIN6;
  233.   Result.Address := Address;
  234. end;
  235.  
  236. function IsIPv4Mapped(const IPv6Addr: TNetworkAddress): Boolean;
  237. var
  238.   In6Addr: Sockets.TIn6Addr;
  239. begin
  240.   if IPv6Addr.AddressType = atIN4 then
  241.     Exit(True);
  242.   if IPv6Addr.AddressType  <> atIN6 then
  243.     raise EUnsupportedAddress.Create('Can only check IPv4 mapping for IPv6 addresses');
  244.   IN6Addr := StrToHostAddr6(IPv6Addr.Address);
  245.   Result := (IN6Addr.u6_addr16[0] = 0) and
  246.             (IN6Addr.u6_addr16[1] = 0) and
  247.             (IN6Addr.u6_addr16[2] = 0) and
  248.             (IN6Addr.u6_addr16[3] = 0) and
  249.             (IN6Addr.u6_addr16[4] = 0) and
  250.             (IN6Addr.u6_addr16[5] = $FFFF);
  251. end;
  252.  
  253. function ExtractIPv4Address(const IPv6Addr: TNetworkAddress): TNetworkAddress;
  254. var
  255.   In6Addr: Sockets.TIn6Addr;
  256. begin
  257.   if IPv6Addr.AddressType = atIN4 then
  258.     Exit(IPv6Addr);
  259.   if IPv6Addr.AddressType  <> atIN6 then
  260.     raise EUnsupportedAddress.Create('Can only extract IPv4 mapping from IPv6 addresses');
  261.   IN6Addr := StrToHostAddr6(IPv6Addr.Address);
  262.   Result := IN4Address('%d.%d.%d.%d'.Format([IN6Addr.s6_addr8[12],
  263.                                              IN6Addr.s6_addr8[13],
  264.                                              IN6Addr.s6_addr8[14],
  265.                                              IN6Addr.s6_addr8[15]]));
  266. end;
  267.  
  268. function IN6Equal(const A, B: String): Boolean;
  269. var
  270.   AAddr, BAddr: Sockets.Tin6_addr;
  271. begin
  272.   AAddr := StrToHostAddr6(A);
  273.   BAddr := StrToHostAddr6(B);
  274.   Result := (AAddr.s6_addr32[0] = BAddr.s6_addr32[0]) and
  275.             (AAddr.s6_addr32[1] = BAddr.s6_addr32[1]) and
  276.             (AAddr.s6_addr32[2] = BAddr.s6_addr32[2]) and
  277.             (AAddr.s6_addr32[3] = BAddr.s6_addr32[3]);
  278. end;
  279.  
  280. operator=(const A, B: TNetworkAddress): Boolean;
  281. begin
  282.   Result := (A.AddressType = B.AddressType) and (
  283.               ((A.AddressType = atIN4) and (A.Address = B.Address)) or // IPv4: simple string equality
  284.               ((A.AddressType = atIN6) and IN6Equal(A.Address, B.Address)) // IPv6 check binary equality
  285.             );
  286. end;
  287.  
  288. operator:=(const AStr: String): TNetworkAddress;
  289. begin
  290.   Result := INAddr(AStr);
  291. end;
  292.  
  293. function TCPSocket(AType: TSocketType): TSocket;
  294. begin
  295.   Result.SocketType := AType;
  296.   Result.FD := CreateSocketFD(AType, SOCK_STREAM, 0);
  297. end;
  298.  
  299. function UDPSocket(AType: TSocketType): TSocket;
  300. begin
  301.   Result.SocketType := AType;
  302.   Result.FD := CreateSocketFD(AType, SOCK_DGRAM, 0);
  303. end;
  304.  
  305. procedure CloseSocket(const ASocket: TSocket);
  306. begin
  307.   Sockets.CloseSocket(ASocket.FD);
  308. end;
  309.  
  310. procedure Bind(const ASocket: TSocket; const AAddress: TNetworkAddress;
  311.   APort: Word);
  312. var
  313.   addr: _TAddressUnion;
  314. begin
  315.   FillAddr(AAddress, APort, @addr, ASocket.SocketType = stDualStack);
  316.   if fpbind(ASocket.FD, @addr, SizeOf(addr)) <> 0 then raise
  317.     ESocketError.Create(socketerror, 'bind (%s:%d)'.Format([AAddress.Address, APort]));
  318. end;
  319.  
  320. procedure TCPServerListen(const ASocket: TSocket; Backlog: Integer);
  321. begin
  322.   if fplisten(ASocket.FD, Backlog) <> 0 then raise
  323.     ESocketError.Create(socketerror, 'listen');
  324. end;
  325.  
  326. function TCPReceive(const ASocket: TSocket; ABuffer: Pointer; MaxSize: SizeInt;
  327.   AFlags: Integer): SizeInt;
  328. begin
  329.   Result := fprecv(ASocket.FD, ABuffer, MaxSize, AFlags);
  330.   if Result = 0 then
  331.     raise EConnectionClosedException.Create('The connection closed')
  332.   else if Result < 0 then
  333.     raise ESocketError.Create(socketerror, 'recv');
  334. end;
  335.  
  336. function UDPReceive(const ASocket: TSocket; ABuffer: Pointer; MaxSize: SizeInt;
  337.   AFlags: Integer): TUDPResult;
  338. var
  339.   {$IfNDef WINDOWS}
  340.   _addr: _TAddressUnion;
  341.   _addrLen: SizeInt;
  342.   {$EndIf}
  343.   addr: _PAddressUnion;
  344.   addrLen: PSizeInt;
  345. begin
  346.   {$IfDef WINDOWS}
  347.   // WinSock doesn't like the addr located on the stack, therefore we create a heap instance for it
  348.   New(addr);
  349.   New(addrLen);
  350.   try
  351.   {$Else}
  352.   addr := @_addr;
  353.   addrLen := @_addrLen;
  354.   {$EndIf}
  355.   addrLen^ := SizeOf(_TAddressUnion);
  356.   Result.DataSize := fprecvfrom(ASocket.FD, ABuffer, MaxSize, AFlags, Sockets.PSockAddr(addr), addrLen);
  357.   if Result.DataSize < 0 then
  358.     raise ESocketError.Create(socketerror, 'recvfrom');
  359.   ReadAddr(addr, ASocket.SocketType = stDualStack, Result.FromAddr, Result.FromPort);
  360.   {$IfDef WINDOWS}
  361.   finally
  362.     Dispose(addr);
  363.     Dispose(addrLen);
  364.   end;
  365.   {$EndIf}
  366. end;
  367.  
  368. function TCPSend(const ASocket: TSocket; ABuffer: Pointer; ASize: SizeInt;
  369.   AFlags: Integer): SizeInt;
  370. begin
  371.   Result := fpsend(ASocket.FD, ABuffer, ASize, AFlags);
  372.   if Result < 0 then
  373.     raise ESocketError.Create(socketerror, 'send');
  374. end;
  375.  
  376. function UDPSend(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress;
  377.   ReceiverPort: Word; ABuffer: Pointer; ASize: SizeInt; AFlags: Integer
  378.   ): SizeInt;
  379. var
  380.   addr: _TAddressUnion;
  381. begin
  382.   FillAddr(ReceiverAddr, ReceiverPort, @addr, ASocket.SocketType = stDualStack);
  383.   Result := fpsendto(ASocket.FD, ABuffer, ASize, AFlags, @addr, SizeOf(addr));
  384.   if Result < 0 then
  385.     raise ESocketError.Create(socketerror, 'sendto');
  386. end;
  387.  
  388. function TCPReceiveStr(const ASocket: TSocket; MaxLength: SizeInt;
  389.   AFlags: Integer): String;
  390. var
  391.   Len: SizeInt;
  392. begin
  393.   Result := '';
  394.   SetLength(Result, MaxLength);
  395.   Len := TCPReceive(ASocket, @Result[1], MaxLength, AFlags);
  396.   SetLength(Result, Len);
  397. end;
  398.  
  399. function UDPReceiveStr(const ASocket: TSocket; MaxLength: SizeInt;
  400.   AFlags: Integer): TUDPStringMessage;
  401. var
  402.   UdpMessage: TUDPResult;
  403. begin
  404.   Result := Default(specialize TUDPDataMessage<String>);
  405.   SetLength(Result.Data, MaxLength);
  406.   UdpMessage := UDPReceive(ASocket, @Result.Data[1], MaxLength, AFlags);
  407.   SetLength(Result.Data, UdpMessage.DataSize);
  408.   Result.FromAddr := UdpMessage.FromAddr;
  409.   Result.FromPort := UdpMessage.FromPort;
  410. end;
  411.  
  412. function TCPSendStr(const ASocket: TSocket; const AData: String; AFlags: Integer
  413.   ): SizeInt;
  414. begin
  415.   if Length(AData) = 0 then Exit(0);
  416.   Result := TCPSend(ASocket, @AData[1], Length(AData), AFlags);
  417. end;
  418.  
  419. function UDPSendStr(const ASocket: TSocket;
  420.   const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: String; AFlags: Integer
  421.   ): SizeInt;
  422. begin
  423.   if Length(AData) = 0 then Exit(0);
  424.   Result := UDPSend(ASocket, ReceiverAddr, ReceiverPort, @AData[1], Length(AData), AFlags);
  425. end;
  426.  
  427. generic function TCPReceive<T>(const ASocket: TSocket; AFlags: Integer = 0): T;
  428. var
  429.   Len: SizeInt;
  430. begin
  431.   Result := Default(T);
  432.   Len := 0;
  433.   while Len < SizeOf(Result) do
  434.     Len += TCPReceive(ASocket, @PByte(@Result)[Len], SizeOf(Result) - Len, AFlags);
  435. end;
  436.  
  437. generic function UDPReceive<T>(const ASocket: TSocket; AFlags: Integer = 0): specialize TUDPDataMessage<T>;
  438. var
  439.   UdpMessage: TUDPResult;
  440. begin
  441.   Result := Default(T);
  442.   UdpMessage := UDPReceive(ASocket, @Result, SizeOf(Result), AFlags);
  443.   if UdpMessage.DataSize < SizeOf(T) then
  444.     raise EUDPFragmentationException.Create('Receiving of fragmented data is not supported by typed receive');
  445.   Result.FromAddr := UdpMessage.FromAddr;
  446.   Result.FromPort := UdpMessage.FromPort;
  447. end;
  448.  
  449. generic function TCPSend<T>(const ASocket: TSocket; constref AData: T; AFlags: Integer = 0): SizeInt;
  450. begin
  451.   Result := TCPSend(ASocket, @AData, SizeOf(T), AFlags);
  452. end;
  453.  
  454. generic function UDPSend<T>(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; constref AData: T; AFlags: Integer = 0): SizeInt;
  455. begin
  456.   Result := UDPSend(ASocket, ReceiverAddr, ReceiverPort, @AData, SizeOf(T), AFlags);
  457. end;
  458.  
  459. generic function TCPReceiveArray<T>(const ASocket: TSocket; MaxCount: SizeInt; AFlags: Integer = 0): specialize TArray<T>;
  460. var
  461.   Len: SizeInt;
  462. begin    
  463.   Result := nil;
  464.   SetLength(Result, MaxCount);
  465.   Len := 0;
  466.   repeat
  467.     Len += TCPReceive(ASocket, @PByte(@Result)[Len], MaxCount * SizeOf(T) - Len, AFlags);
  468.   until (Len mod SizeOf(T)) = 0;
  469.   SetLength(Result, Len div SizeOf(T));
  470. end;
  471.  
  472. generic function UDPReceiveArray<T>(const ASocket: TSocket; MaxCount: SizeInt; AFlags: Integer = 0): specialize TUDPDataMessage<specialize TArray<T>>;
  473. var
  474.   UdpMessage: TUDPResult;
  475. begin
  476.   Result.Data := nil;
  477.   SetLength(Result.Data, MaxCount);
  478.   UdpMessage := UDPReceive(ASocket, @Result.Data[0], MaxCount * SizeOf(T), AFlags);
  479.   if UdpMessage.DataSize mod SizeOf(T) > 0 then
  480.     raise EUDPFragmentationException.Create('Receiving of fragmented data is not supported by typed receive');
  481.   SetLength(Result.Data, UdpMessage.DataSize div SizeOf(T));
  482.   Result.FromAddr := UdpMessage.FromAddr;
  483.   Result.FromPort := UdpMessage.FromPort;
  484. end;
  485.  
  486. generic function TCPSendArray<T>(const ASocket: TSocket; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt;
  487. begin
  488.   if Length(AData) = 0 then Exit(0);
  489.   Result := TCPSend(ASocket, @AData[0], Length(AData) * SizeOf(T), AFlags);
  490. end;
  491.  
  492. generic function UDPSendArray<T>(const ASocket: TSocket; const ReceiverAddr: TNetworkAddress; ReceiverPort: Word; const AData: specialize TArray<T>; AFlags: Integer = 0): SizeInt;
  493. begin
  494.   if Length(AData) = 0 then Exit(0);
  495.   Result := UDPSend(ASocket, ReceiverAddr, ReceiverPort, @AData[0], Length(AData) * SizeOf(T), AFlags);
  496. end;
  497.  
  498. function DataPending(const ASocket: TSocket; TimeOut: Integer): Boolean;
  499. var
  500.   FDSet: TFDSet;
  501.   timeval: TTimeVal;
  502.   Ret: LongInt;
  503. begin
  504.   {$IfDef UNIX}fp{$endif}FD_ZERO(FDSet);
  505.   {$IfDef UNIX}fp{$endif}FD_SET(ASocket.FD, FDSet);
  506.   timeval.tv_sec := TimeOut div 1000;
  507.   timeval.tv_usec := (TimeOut mod 1000) * 1000;
  508.   Ret := {$IfDef UNIX}fp{$endif}select(ASocket.FD, @FDSet, nil, nil, @timeval);
  509.   if Ret < 0 then
  510.     raise ESocketError.Create(socketerror, 'select');
  511.   Result := Ret > 0;
  512. end;
  513.  
  514. { ESocketError }
  515.  
  516. constructor ESocketError.Create(ACode: Integer; const FunName: String);
  517. begin
  518.   inherited CreateFmt('[Socket Error: %d] %s call failed',  [ACode, FunName]);
  519.   FCode := ACode;
  520. end;
  521.  
  522. end.

Example:
Code: Pascal  [Select][+][-]
  1. program example;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SimpleSockets;
  7.  
  8. var
  9.   Sock: TSocket;
  10.   Msg: TUDPStringMessage;
  11. begin
  12.   Sock := UDPSocket(stDualStack);
  13.   try
  14.     Bind(Sock, '127.0.0.1', 1337);
  15.     // Simple echo server: Receive message and answer with same message
  16.     Msg := UDPReceiveStr(Sock);
  17.     WriteLn('Received from Client at ', Msg.FromAddr.Address, ':', Msg.FromPort,' message: ', Msg.Data);
  18.     UDPSendStr(Sock, Msg.FromAddr, Msg.FromPort, Msg.Data);
  19.   finally
  20.     CloseSocket(Sock);
  21.   end;
  22.   ReadLn;
  23. end.
To use just copy the unit into your project and get started

PS: this is something I wanted to do for quite some time, it is basically the AsyncNet version just not asynchronous. Because I think using sockets for small things (like a small UDP client or server) is way to complicated right now. But it defenitely needs completion, as it just contains the basic socket functions
Also this was a test about DualStack implementations I wanted to improve in asyncnet, and this seems to work quite well and transparently

@prodingus
Feel free to use it, did some simple tests and at least for this it works quite well
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 10:27:21 pm
I also made a very very very crude sample.

Sender and Receiver.
At least this will print out the errors TS might get.

Code: Pascal  [Select][+][-]
  1. program Sender;
  2. uses
  3.   SysUtils, crt, sockets;
  4. const
  5.   UDPPackLen = 512;
  6. var
  7.   sock: Tsocket;
  8.   buff: array[0..UDPPackLen - 1] of char;
  9.   ServerAddr: sockaddr_in;
  10.   MessageSize: SizeInt;
  11. begin
  12.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  13.   assert(sock <> -1);
  14.   ServerAddr.sin_family := AF_INET;
  15.   ServerAddr.sin_addr := StrToNetAddr('192.168.2.11'); // server IP
  16.   ServerAddr.sin_port := htons(1234); // server port
  17.   // if fpbind(sock, @ServerAddr, SizeOf(ServerAddr)) = 0 then
  18.   if fpconnect(sock, @ServerAddr, SizeOf(ServerAddr)) = 0 then
  19.   begin
  20.     repeat
  21.       buff := timetostr(now) + #0;
  22.       MessageSize := fpsend(Sock, @Buff[0], 9, 0);
  23.       if MessageSize = -1 then
  24.       begin
  25.         writeln(socketError);
  26.       end
  27.       else
  28.       begin
  29.         writeln('Sending: ' + timetostr(now) + ' ' + MessageSize.ToString);
  30.       end;
  31.       sleep(100);
  32.     until False;
  33.   end
  34.   else
  35.   begin
  36.     writeln(socketError);
  37.     readln;
  38.   end;
  39. end.

Code: Pascal  [Select][+][-]
  1. program Receiver;
  2. uses
  3.   SysUtils, crt, sockets;
  4. const
  5.   UDPPackLen = 512;
  6. var
  7.   sock: Tsocket;
  8.   buff: array[0..UDPPackLen - 1] of char;
  9.   ServerAddr: sockaddr_in;
  10.   MessageSize: SizeInt;
  11.   outp: string;
  12. begin
  13.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  14.   assert(sock <> -1);
  15.   ServerAddr.sin_family := AF_INET;
  16.   ServerAddr.sin_addr := StrToNetAddr('192.168.2.11'); // server IP
  17.   ServerAddr.sin_port := htons(1234); // server port
  18.   if fpbind(sock, @ServerAddr, SizeOf(ServerAddr)) = 0 then
  19.   begin
  20.     repeat
  21.       MessageSize := fprecv(sock, @buff, SizeOf(buff), 0);
  22.       if MessageSize = -1 then
  23.       begin
  24.         writeln(socketError);
  25.       end
  26.       else
  27.       begin
  28.         SetString(outp, pansichar(@buff[0]), 8);
  29.         writeln('Received: ' + outp);
  30.       end;
  31.       sleep(100);
  32.     until False;
  33.   end
  34.   else
  35.   begin
  36.     writeln(socketError);
  37.     readln;
  38.   end;
  39. end.

Works fine here (after allowing communication through the firewall).
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 02, 2022, 10:57:01 pm
Because I think using sockets for small things (like a small UDP client or server) is way to complicated right now. But it defenitely needs completion, as it just contains the basic socket functions

UDP (and the equivalents via unix-domain sockets and whatever Windows offers these days) is vastly underused.

But what would be really useful is a subset SCTP (message-oriented but reliable) which was also small enough to put on e.g. an Arduino endpoint.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 11:18:45 pm
Quote
The socketError will give you more information when your fpbind() fails.

this is the problem! it returns 10022 error. The code is running ON THE "SERVER" and the ip of that "server" is 1.1.1.2.  %). Also, no firewall.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 02, 2022, 11:36:38 pm
This error is the EINVAL error, from the WinSock2 Documentation for bind:
Quote
An invalid argument was supplied.

This error is returned of the socket s is already bound to an address.

Is the code you posted previously the exact code that results in this error?
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 11:39:29 pm
Quote
The rather hackish way I'd do it would be something like

Code: Pascal  [Select][+][-]
  1.     uses
  2.       sockets;
  3.      
  4.     const
  5.       UDPPackLen = 512;
  6.  
  7.     var
  8.       sock: Tsocket;
  9.       buff: String;
  10.       ServerAddr, FromAddr: sockaddr_in;
  11.       FromAddrLen: Integer;
  12.       ClientAddr: String;
  13.       ClientPort: Word;
  14.       MessageSize: SizeInt;
  15.     begin
  16.       // Start UDP Server
  17.       sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  18.       ServerAddr.sin_family:= AF_INET;
  19.       ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  20.       ServerAddr.sin_port := 531; // server port
  21.       fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  22.       // Receive Data
  23.       SetLength(buff, UDPPackLen);
  24.       MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  25.       SetLength(buff, MessageSize);
  26.       ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  27.       ClientPort := NToHs(FromAddr.sin_port);
  28.       WriteLn(buff)
  29.     end.

even this returns 10022
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 11:41:23 pm
Quote
The socketError will give you more information when your fpbind() fails.

this is the problem! it returns 10022 error. The code is running ON THE "SERVER" and the ip of that "server" is 1.1.1.2.  %). Also, no firewall.
Did you also try my same Sender code I gave you?
Or are you using your own (which we haven't seen yet)?

Just try my Sender and Reciever code.

Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 02, 2022, 11:43:57 pm
Quote
Is the code you posted previously the exact code that results in this error?

Quote
Did you also try my same Sender code I gave you?

Yes its the same code (before the sender receiver, I haven't tried them yet). And I did a system reboot. Nothing else networking is running.


Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 02, 2022, 11:48:22 pm
The error is not the bind but the recvfrom, and the error here is because thanks to some weird quirk of WinSock, recvfrom does not like it if the address is located on the stack (or unaligned memory in general).

The quick solution to this is to put the address and length on the heap:
Code: Pascal  [Select][+][-]
  1.         uses
  2.           sockets;
  3.          
  4.         const
  5.           UDPPackLen = 512;
  6.      
  7.         var
  8.           sock: Tsocket;
  9.           buff: String;
  10.           ServerAddr: sockaddr_in;
  11.           FromAddr: Psockaddr_in;
  12.           FromAddrLen: PInteger;
  13.           ClientAddr: String;
  14.           ClientPort: Word;
  15.           MessageSize: SizeInt;
  16.         begin
  17.           // Start UDP Server
  18.           sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  19.           ServerAddr.sin_family:= AF_INET;
  20.           ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  21.           ServerAddr.sin_port := 531; // server port
  22.           fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  23.           // Receive Data
  24.           SetLength(buff, UDPPackLen);
  25.           new(FromAddr);
  26.           new(FromAddrLen);
  27.           try
  28.             FromAddrLen^ := SizeOf(FromAddr^);
  29.             MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  30.             SetLength(buff, MessageSize);
  31.             ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  32.             ClientPort := NToHs(FromAddr.sin_port);
  33.           finally
  34.             Dispose(FromAddr);
  35.             Dispose(FromAddrLen);
  36.           end;
  37.           WriteLn(buff)
  38.         end.

It's just a very weird windows thing, best to not think to much about

Or, as stated above, youse the Unit I posted above: https://github.com/Warfley/PasSimpleSockets/blob/master/simplesockets.pas (example: https://github.com/Warfley/PasSimpleSockets/blob/master/examples/udpechoserver.pas) which also does handle this (as I have encountered this already quite often)
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 02, 2022, 11:54:04 pm
The error is not the bind but the recvfrom, and the error here is because thanks to some weird quirk of WinSock, recvfrom does not like it if the address is located on the stack (or unaligned memory in general).
The code I gave didn't use fprecvfrom but fprecv.
So I wonder if TS used my code or again some own changed version?
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 12:19:33 am
Quote
The error is not the bind but the recvfrom, and the error here is because thanks to some weird quirk of WinSock, recvfrom does not like it if the address is located on the stack (or unaligned memory in general).

The quick solution to this is to put the address and length on the heap:

Code: Pascal  [Select][+][-]
  1. new(FromAddr);
  2. new(FromAddrLen);
after this I get again error 10022.

Also after your modifications the lines:
Code: Pascal  [Select][+][-]
  1. ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  2. ClientPort := NToHs(FromAddr.sin_port);
produce error
sockets_1.lpr(41,42) Fatal: Syntax error, ")" expected but "identifier SIN_ADDR" found
sockets_1.lpr(41,42) Fatal: Syntax error, ")" expected but "identifier SIN_PORT" found
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 12:28:34 am
Yeah my bad it must be:
Code: Pascal  [Select][+][-]
  1. MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, FromAddr, FromAddrLen);
  2.             SetLength(buff, MessageSize);
  3.             ClientAddr := NetAddrToStr(FromAddr^.sin_addr);
  4.             ClientPort := NToHs(FromAddr^.sin_port);
As they are now pointer
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 12:31:19 am
Why are you even using fprecvfrom while you don't do anything with the from data?

You can just use fprecv without the fromaddr like I showed in my example.

Did you try my exact code yet?
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 12:47:59 am
I think that it is quite important to get recvfrom working, because a UDP server that is not capable of answering is probably quite pointless.

What would be the point if he could get this running using recv when at some point he will need recvfrom probably anyway?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 12:54:01 am
What would be the point if he could get this running using recv when at some point he will need recvfrom probably anyway?
Because the fromadress was already known. It's always the server.

TS hasn't really mentioned what this is used for but from the code it is clear the server is 1.1.1.2.
So the address to anwer to is known.

a client loop that  sends continiously a message (to an ip,port),
and a server loop that listens (receives) for any messages

Ps, I am noob at networking.
Side note: I am using 2 windows 7 vms,  ips are 1.1.1.1 and 1.1.1.2, no firewall.

Besides that... If my code also generates a 10022 error there is something else wrong and it has nothing to do with recvfrom. If it works we can expand it with recvfrom if needed



Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 03, 2022, 09:33:21 am
You can just use fprecv without the fromaddr like I showed in my example.

Did you try my exact code yet?

I'd suggest apart from anything else that it's a matter of /courtesy/ to do so, before complaining of ongoing problems.

I agree that RecvFrom() might turn out to be needed as part of the bigger picture, but the first step is to verify that addresses etc. are OK.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 11:21:49 am
Because the fromadress was already known. It's always the server.
At least one of us has a misunderstanding here, because I understood it as if he is currently writing the server, and the server probably needs to use recvfrom to identify the client

Besides that... If my code also generates a 10022 error there is something else wrong and it has nothing to do with recvfrom. If it works we can expand it with recvfrom if needed
I could reproduce this error on my machine, and as I already stated, the problem with stack pointers for the memory is something that is known for the winapi for quite some time (and took me a many hours to find out when I first encountered it).
But with this code it works on my machine:
Code: Pascal  [Select][+][-]
  1. uses
  2.   sockets;
  3.  
  4. const
  5.   UDPPackLen = 512;
  6.  
  7. var
  8.   sock: Tsocket;
  9.   buff: String;
  10.   ServerAddr: sockaddr_in;
  11.   FromAddr: psockaddr_in;
  12.   FromAddrLen: PInteger;
  13.   ClientAddr: String;
  14.   ClientPort: Word;
  15.   MessageSize: SizeInt;
  16. begin
  17.   // Start UDP Server
  18.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  19.   ServerAddr.sin_family:= AF_INET;
  20.   ServerAddr.sin_addr := StrToNetAddr('127.0.0.1'); // server IP
  21.   ServerAddr.sin_port := 531; // server port
  22.   fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  23.   // Receive Data
  24.   SetLength(buff, UDPPackLen);
  25.   new(FromAddr);
  26.   new(FromAddrLen);
  27.   try
  28.     FromAddrLen^ := SizeOf(FromAddr^);
  29.     MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, psockaddr(FromAddr), FromAddrLen);
  30.     WriteLn('err: ', socketerror);
  31.     SetLength(buff, MessageSize);
  32.     ClientAddr := NetAddrToStr(FromAddr^.sin_addr);
  33.     ClientPort := NToHs(FromAddr^.sin_port);
  34.   finally
  35.     Dispose(FromAddr);
  36.     Dispose(FromAddrLen);
  37.   end;
  38.   WriteLn(buff);
  39.   ReadLn;
  40. end.
  41.      


Of course the IP needs to be changed (I don't have IP 1.1.1.2)

PS: @TE are you shure you have IP 1.1.1.2, because as far as I know the 1.1.1.x IP range is owned by Cloudflare, who host their infrastructure their (as low ip numbers are a few nanoseconds faster than high ones in switching, to give them more performance for their CDN services)
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 11:42:18 am
@Warfley. I didn't get a 10022 but a 10014 error with the fprecvfrom.

To solve this I didn't need to create FromAddr but could just leave it on the stack.
But you DO need to provide the correct FromAddrLen for it.
(And that was missing from the original code)

So here my code with fprecvfrom (with error checking).

Code: Pascal  [Select][+][-]
  1. program Receiver;
  2. uses
  3.   SysUtils, crt, sockets;
  4. const
  5.   UDPPackLen = 512;
  6. var
  7.   sock: Tsocket;
  8.   buff: array[0..UDPPackLen - 1] of char;
  9.   ServerAddr: sockaddr_in;
  10.   FromAddr: sockaddr_in;
  11.   FromAddrLen: Integer;
  12.   MessageSize: SizeInt;
  13.   outp: string;
  14. begin
  15.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  16.   assert(sock <> -1);
  17.   ServerAddr.sin_family := AF_INET;
  18.   ServerAddr.sin_addr := StrToNetAddr('192.168.2.11'); // server IP
  19.   ServerAddr.sin_port := htons(1234); // server port
  20.   if fpbind(sock, @ServerAddr, SizeOf(ServerAddr)) = 0 then
  21.   begin
  22.     repeat
  23.       FromAddrLen := SizeOf(FromAddr);
  24.       MessageSize := fprecvfrom(sock, @buff, Length(buff), 0, @FromAddr, @FromAddrLen);
  25.       if MessageSize = -1 then
  26.       begin
  27.         writeln(socketError);
  28.       end
  29.       else
  30.       begin
  31.         SetString(outp, pansichar(@buff[0]), 8);
  32.         writeln('Received: ' + outp + ' ' + NetAddrToStr(FromAddr.sin_addr));
  33.       end;
  34.       sleep(100);
  35.     until False;
  36.   end
  37.   else
  38.   begin
  39.     writeln(socketError);
  40.     readln;
  41.   end;
  42. end.

Quote
Received: 11:46:49 192.168.2.11
Received: 11:46:49 192.168.2.11
Received: 11:46:49 192.168.2.11
Received: 11:46:49 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:50 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11
Received: 11:46:51 192.168.2.11

Edit:

Changing your code back to local variables it also works fine as long as you set FromAddrLen.
The moment you remove line 23 you'll get a 10014.
I think in this code the local variables are already always correctly aligned.
You do have a point that they could be misaligned but that's not the case here.

Code: Pascal  [Select][+][-]
  1. uses
  2.   sockets;
  3. const
  4.   UDPPackLen = 512;
  5. var
  6.   sock: Tsocket;
  7.   buff: String;
  8.   ServerAddr: sockaddr_in;
  9.   FromAddr: sockaddr_in;
  10.   FromAddrLen: Integer;
  11.   ClientAddr: String;
  12.   ClientPort: Word;
  13.   MessageSize: SizeInt;
  14. begin
  15.   // Start UDP Server
  16.   sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  17.   ServerAddr.sin_family:= AF_INET;
  18.   ServerAddr.sin_addr := StrToNetAddr('192.168.2.11'); // server IP
  19.   ServerAddr.sin_port := htons(1234); // server port
  20.   fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  21.   // Receive Data
  22.   SetLength(buff, UDPPackLen);
  23.   FromAddrLen := SizeOf(FromAddr);
  24.   MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  25.   WriteLn('err: ', socketerror);
  26.   SetLength(buff, MessageSize);
  27.   ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  28.   ClientPort := NToHs(FromAddr.sin_port);
  29.   WriteLn(buff);
  30.   ReadLn;
  31. end.

Quote
err: 0
11:56:52

Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 06:22:27 pm
Code: Pascal  [Select][+][-]
  1. program send_data_test;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.         sysutils, crt, lnet;
  5. var
  6.         Sock:TLUDP;
  7.         i,j,k:integer;
  8.  
  9.  
  10. begin
  11.         i:=0;
  12.  
  13.  
  14.         Sock:= TLUdp.Create(nil);
  15.         Sock.connect('1.1.1.2', 1234);
  16.  
  17.  
  18.         repeat begin
  19.  
  20.                 sock.sendmessage(inttostr(i+5));
  21.                 i:=i+1;
  22.                 writeln(i,' ', inttostr(i+5));
  23.  
  24.                 sleep(10);
  25.  
  26.         end; until keypressed=true;
  27.  
  28.         readln;
  29.  
  30. end.

the client,


Code: Pascal  [Select][+][-]
  1. program sockets_1;
  2.  
  3. uses
  4.         sysutils, crt, sockets;
  5.  
  6. const
  7.   UDPPackLen = 512;
  8. var
  9.         i:integer;
  10.   sock: Tsocket;
  11.   buff: string;
  12.  
  13.   outp:string;
  14.  
  15.   ServerAddr: sockaddr_in;
  16.   FromAddr:  sockaddr_in;
  17.   FromAddrLen: Integer;
  18.   ClientAddr: String;
  19.   ClientPort: Word;
  20.   MessageSize: SizeInt;
  21. begin
  22.  
  23.     i:=0;
  24.         // Start UDP Server
  25.         sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  26.         ServerAddr.sin_family:= AF_INET;
  27.         ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  28.         ServerAddr.sin_port := htons(1234); // server port
  29.         fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  30.  
  31.         writeln(sock <> -1);
  32.         writeln(socketError);
  33.  
  34.         // Receive Data
  35.         SetLength(buff, UDPPackLen);
  36.         FromAddrLen := SizeOf(FromAddr);
  37.         writeln(socketError);
  38.  
  39.                 MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  40.                 //WriteLn('err: ', socketerror);
  41.                 SetLength(buff, MessageSize);
  42.                 ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  43.                 ClientPort := NToHs(FromAddr.sin_port);
  44.         repeat begin
  45.                 SetLength(buff, MessageSize);
  46.                 MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  47.  
  48.                 i:=i+1;
  49.                 WriteLn(i,' ',buff);
  50.                 sleep(100);
  51.         end; until false;
  52.         ReadLn;
  53.  
  54.  
  55. end.
  56.  

the server.

The client sends with sleep(10) and the server receives (YES, its working!!!) with sleep(100).
The problem 1 is that the server keeps receiving even after I stop client, and 2 the received messages stop at 10 (displays only 1 and for 11+ displays nothing). The +5 was just for check, no other reason.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 03, 2022, 06:24:34 pm
The problem 1 is that the server keeps receiving even after I stop client

What do you mean?

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 06:32:53 pm
The client sends with sleep(10) and the server receives (YES, its working!!!) with sleep(100).
The problem 1 is that the server keeps receiving even after I stop client, and 2 the received messages stop at 10 (displays only 1 and for 11+ displays nothing). The +5 was just for check, no other reason.
1) UDP also has a buffer so it's usual you would end up with additional message if your sender is faster than the receiver.

2) You have a  SetLength(buff, MessageSize); on line 45. But MessageSize is the result of the previous fprecvfrom !!!
So the MessageSize could be 0. You need to do a SetLength(buff, UDPPackLen); before the fprecvfrom to make room for the string AND a SetLength(buff, MessageSize); to cut the buffer/string to the correct received size after the fprecvfrom.

So somthing like this:

Code: Pascal  [Select][+][-]
  1. i:=0;
  2. // Start UDP Server
  3. sock := fpsocket(AF_INET, SOCK_DGRAM, 0);
  4. ServerAddr.sin_family:= AF_INET;
  5. ServerAddr.sin_addr := StrToNetAddr('1.1.1.2'); // server IP
  6. ServerAddr.sin_port := htons(1234); // server port
  7. fpbind(sock, @ServerAddr, SizeOf(ServerAddr));
  8.  
  9. repeat
  10.   SetLength(buff, UDPPackLen);
  11.   MessageSize := fprecvfrom(sock, @buff[1], Length(buff), 0, @FromAddr, @FromAddrLen);
  12.   SetLength(buff, MessageSize);
  13.  
  14.   ClientAddr := NetAddrToStr(FromAddr.sin_addr);
  15.   ClientPort := NToHs(FromAddr.sin_port);
  16.  
  17.   i:=i+1;
  18.   WriteLn(i,' ',buff);
  19.   sleep(100);
  20. until false;

No need to do the first fprecvfrom you have above the repeat.
And no need to wrap the code inside repeat/until in begin/end.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 03, 2022, 06:40:17 pm
You need to do a SetLength(buff, UDPPackLen); before the fprecvfrom to make room for the string AND a SetLength(buff, MessageSize); to cut the buffer/string to the correct received size after the fprecvfrom.

As in my original example. Also I'd note that I've edited that to use AnsiString, lest any "extended ASCII" characters appear and cause confusion.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 06:46:43 pm
Quote
What do you mean?
The client sends fast and the server receives slower (seems to receive slower because of sleep(100)); as rvk said, its a buffer.

Quote
2) You have a  SetLength(buff, MessageSize); on line 45. But MessageSize is the result of the previous fprecvfrom !!!
So the MessageSize could be 0. You need to do a SetLength(buff, UDPPackLen); before the fprecvfrom to make room for the string AND a SetLength(buff, MessageSize); to cut the buffer/string to the correct received size after the fprecvfrom.

yes, that did the trick.

The thing with the buffer, does it have anything to do with synchronous/asynchronous? I thought that udp packets, if you don't receive them in time, you loose them.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 06:55:58 pm
The thing with the buffer, does it have anything to do with synchronous/asynchronous? I thought that udp packets, if you don't receive them in time, you loose them.
No. Buffering is normal. I'm not sure how large the buffer for udp socket is on Windows but there are also some other buffers at play. Buffer in the network adapter for example.

So, although UDP reception is not guaranteed, the reliabilty of receiving them can be quite high. Just make sure your reception is fast enough (or at least faster than your sending).
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 07:13:17 pm
It seems that the communication is reliable, with one quirk: the last message is not received, althout the client seems to have send it judging from the client's output (must be the repeat loop?).

The problem with the buffer is this: I wanted to make the client send message 1 to the server, then when the server received the message 1, send a message 2 to client, and again when the client received the message 2 send a new message 3 to server and so on. A ping-pong as fast as the connection (hops, latency) can be (2 vms using their dedicated virtual adapter should be quite fast).
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 07:17:13 pm
The problem with the buffer is this: I wanted to make the client send message 1 to the server, then when the server received the message 1, send a message 2 to client, and again when the client received the message 2 send a new message 3 to server and so on. A ping-pong as fast as the connection (hops, latency) can be (2 vms using their dedicated virtual adpater should be quite fast).
Then why are you using UDP and not TCP connection?

You can simulate it by sending an UDP message back and only send the next message when you get the ACK (acknowledgement) back but that will slow down things. A direct TCP connection seems much more appropriate for your description.

BTW. You increase the I after sending but before printing to screen so you actually didn't send that last printed number.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 07:17:33 pm
The problem 1 is that the server keeps receiving even after I stop client, and 2 the received messages stop at 10 (displays only 1 and for 11+ displays nothing). The +5 was just for check, no other reason.
That is the nature of UDP. UDP is connectionless, meaning you just receive datagrams, no matter from which client and what the client state is, and also it is unreliable, meaning that data can get lost.
If you want to know when the client disconnects, and you require reliable transmission, you shouldn't use UDP
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 07:24:32 pm
Quote
Then why are you using UDP and not TCP connection?
I am going to try the ping-pong. I want to use udp instead of tcp because I want to have as low lag as possible. What I am going to do if a packet is lost is up to me to make or not a custom ack/resend.

Quote
ou can simulate it by sending an UDP message back and only send the next message when you get the ACK (acknowledgement) back but that will slow down things.
Does udp return ack by itself?

Quote
BTW. You increase the I after sending but before printing to screen so you actually didn't send that last printed number.
AGAIN, correct!!!

Quote
If you want to know when the client disconnects, and you require reliable transmission, you shouldn't use UDP

I don't mind that (at least yet).
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 07:30:19 pm
Does udp return ack by itself?
No, that's the whole point of UDP.
No return message and no guarantee someone receives the message.

The upside is that you can also send an UDP message to the whole network (broadcast) without knowing any of their IPs. Receivers can answer that they received it (via return UDP message or TCP connection request).



Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 07:35:52 pm
Quote
No, that's the whole point of UDP.
No return message and no guarantee someone receives the message.
That's what I thought, I missinterpreted what you wrote before.

Quote
The upside is that you can also send an UDP message to the whole network (broadcast) without knowing any of their IPs. Receivers can answer that they received it (via return UDP message or TCP connection request).
I am aware of that.

Back to the buffer thing, let's say I want the packets to be droped if the server does not receive them in time. How to do that?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 07:39:44 pm
Back to the buffer thing, let's say I want the packets to be droped if the server does not receive them in time. How to do that?
Send a timestamp with the UDP message from the sender and ignore it on the receiving end if it's too old. That would mean that both computers need to be exact in timesettings.

So, what us your definition of "receive them in time" ?
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 07:47:37 pm
Timestamp will add small latency to the program. Receive them in time = receive when the datagram has arrived at the destination and the program reads it. I might have wrong assumptions on how things work. I thought that a udp datagram arrives, if you read it fast, then good, else the packet is gone/replaced by the next one. I set the server to sleep(1000), I still received all the datagrams.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 07:52:13 pm
There is more than just UDP and TCP, there are things in between
TCP is a reliable ordered stream of data. UDP is for transmitting unreliable unordered packages. There is also RDM (Reliable Delivered Messages), which sends acks and has therefore delivery guarantees, but does not guarantee order, or SEQPACKET (Sequenced Packet), which also ensures ordering and is like TCP also connection based, but unlike TCP it does not provide a stream of data but only single packets, and therefore is more lightweight. Depending on how much guarantees you need and also how much overhead they imply, they can be useful choices as in-between options.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 03, 2022, 07:55:44 pm
Timestamp will add small latency to the program. Receive them in time = receive when the datagram has arrived at the destination and the program reads it. I might have wrong assumptions on how things work. I thought that a udp datagram arrives, if you read it fast, then good, else the packet is gone/replaced by the next one. I set the server to sleep(1000), I still received all the datagrams.
If you are requiring these timing guarantees that the delay of checking a timestamp is crucial, then forget about working with the socket api all together. You either need to use user-space networking, or write your code as a kernel module.
Also you will probably run into scheduling problems as you don't use a real-time operating system
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 03, 2022, 07:57:27 pm
The upside is that you can also send an UDP message to the whole network (broadcast) without knowing any of their IPs. Receivers can answer that they received it (via return UDP message or TCP connection request).

Careful there. Some of this might be OS-specific, but generally speaking UDP broadcasts don't go through routers unless there's a special proxy or similar.

The overwhelming reason for UDP- apart from efficiency- is that (small) messages are received without artificial fragmentation or concatenation.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 08:04:09 pm
Quote
There is more than just UDP and TCP, there are things in between
TCP is a reliable ordered stream of data. UDP is for transmitting unreliable unordered packages. There is also RDM (Reliable Delivered Messages), which sends acks and has therefore delivery guarantees, but does not guarantee order, or SEQPACKET (Sequenced Packet), which also ensures ordering and is like TCP also connection based, but unlike TCP it does not provide a stream of data but only single packets, and therefore is more lightweight. Depending on how much guarantees you need and also how much overhead they imply, they can be useful choices as in-between options.

Nice to know all these info. Of course these can be done manually in order to fit the needs of the program.

Quote
If you are requiring these timing guarantees that the delay of checking a timestamp is crucial, then forget about working with the socket api all together. You either need to use user-space networking, or write your code as a kernel module.
Also you will probably run into scheduling problems as you don't use a real-time operating system
This goes deep into the rabbithole...
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 08:19:43 pm
The upside is that you can also send an UDP message to the whole network (broadcast) without knowing any of their IPs. Receivers can answer that they received it (via return UDP message or TCP connection request).

Careful there. Some of this might be OS-specific, but generally speaking UDP broadcasts don't go through routers unless there's a special proxy or similar.
With whole network I meant if course internal network. For example an internal messaging system.

Timestamp will add small latency to the program.
This could be as little as 4 bytes. So not really any problem considering the UDP is at least package size large.

I thought that a udp datagram arrives, if you read it fast, then good, else the packet is gone/replaced by the next one. I set the server to sleep(1000), I still received all the datagrams.
That's just how it works. An UDP package can even arive seconds later depending on network circumstances, buffering and OS priority.

If that's unacceptable you can send a few bytes extra (it really doesn't take any more space in a package) or leave the concept of UDP behind.

Quote
Then why are you using UDP and not TCP connection?
I am going to try the ping-pong. I want to use udp instead of tcp because I want to have as low lag as possible. What I am going to do if a packet is lost is up to me to make or not a custom ack/resend.
True but in that case you do need to handle receiving messages faster than the sender is sending them. You are not doing that.

You can just flush the buffer after receiving a message. In that case you (might) loose messages but you are more certain the message you do get are more recent.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 08:30:10 pm
Quote
That's just how it works. An UDP package can even arive seconds later depending on network circumstances, buffering and OS priority.

If that's unacceptable you can send a few bytes extra (it really doesn't take any more space in a package) or leave the concept of UDP by behind.

Quote
True but in that case you do need to handle receiving messages faster than the sender is sending them. You are not doing that.

You can just flush the buffer after receiving a message. In that case you (might) loose messages but you are more certain the message you do get are more recent.

The whole point of the sleep(100) and sleep(1000) in the server was to simulate the "packet had arrived and time passed since then so you lost it". It doesn't happen (!). Of course the messages are very small, but unless there is something wrong with the code examples, it seems that udp is not behaving as udp  %)
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 08:38:13 pm
I just come across this nice post and I am going to drop it here:
https://stackoverflow.com/questions/7843644/how-long-does-a-udp-packet-stay-at-a-socket

So to reply to my last post, udp is acting as udp  8)
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 08:38:34 pm
Of course the messages are very small, but unless there is something wrong with the code examples, it seems that udp is not behaving as udp  %)
No, it's not behaving like your notion of UDP.
But your notion is wrong  :D

The buffers are there to make UDP more reliable.
There is nothing in UDP protocol that says messages can't be buffered ir received out of order or after a delay.

Some reading https://jvns.ca/blog/2016/08/24/find-out-where-youre-dropping-packets/

You could just read the buffer until it's empty and ONLY use the last message. In that case you get what you want (or expected). The discarded messages are 'lost'.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 08:40:24 pm
My bad, should have searched before my post #64.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 03, 2022, 09:03:22 pm
I would like to thank everyone in this thread for their contribution and help! I am sure that other dinguses, I mean noobs, I mean newbies would find all that info usefull. :D Let it be no doubt that I did search the references and examples, but they are not always easy to understand (but that's just me).

For the sake of the original post regarding the lnet and the handles, If someone can make an example without using classes, it would be welcome, for I know that you can write things with many different ways. Again, thank you guys!

Ps I am going to test all the examples in this thread, I just need time!
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 03, 2022, 09:54:36 pm
For the sake of the original post regarding the lnet and the handles, If someone can make an example without using classes, it would be welcome, for I know that you can write things with many different ways.
Like it was already said... you can't use lnet without classes.

But I'm curious. You say you want asynchronous communication... Do you know what that means?
Now you have a program with just one flow. Line by Line. You can't achieve asynchrony that way.

Quote
Asynchronous programming is a form of parallel programming that allows a unit of work to run separately from the primary application thread. When the work is complete, it notifies the main thread (as well as whether the work was completed or failed). There are numerous benefits to using it, such as improved application performance and enhanced responsiveness.
https://stackify.com/when-to-use-asynchronous-programming

So if you want to do asynchronous communication, you need to do some form of multiple program flow.

Coming back to your original lnet server (receiver).
Because lnet is event driven you DO need to signal it to do it's work in the background (well not actually background but you need to let it do it's work). You can do that with just one line. Sock.CallAction. So if you add line 13 to your original program, it will work.

(Note that this isn't real asynchronous communication though. You're just misusing the library to force synchronous communications.)

Code: Pascal  [Select][+][-]
  1. program test1;
  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. begin
  10.   Sock := TLUdp.Create(nil);
  11.   Sock.listen(1234);
  12.   repeat
  13.     Sock.CallAction;
  14.     if Sock.GetMessage(tmp) > 0 then
  15.       writeln(tmp);
  16.     sleep(100);
  17.   until False;
  18. end.

Bare in mind... this is not the actual correct way to do things. You are still trying to do a GetMessage while there might not even be a message on the line. This could block the CallAction again and I'm not sure the code will work correctly. The correct way would be to use the sock.OnReceive because then you know there is a message to receive.

Did you look at the example ludp.pp in \config\onlinepackagemanager\packages\lnet\examples\console\ludp ??
It has a complete server/client udp example with a TLUDPTest class.

So the correct way to do it would be something like this:

Code: Pascal  [Select][+][-]
  1. program test1;
  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);
  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.

You see, now when there is no message, CallAction keeps getting called. When there is a message the OnReceive from TMyDummy is called and the message is read and printed. In the example ludp.pp you see you can also send a reply back.

(The TMyDummy can be called something else of course, this is just to show you can use classes, and class procedures, without creating an instance. But that might be something too advanced for now  ;))
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 04, 2022, 10:18:02 pm
Quote
But I'm curious. You say you want asynchronous communication... Do you know what that means?
Now you have a program with just one flow. Line by Line. You can't achieve asynchrony that way.

I read here about it and thougt it will be a good feature.

Quote
(Note that this isn't real asynchronous communication though. You're just misusing the library to force synchronous communications.)
I hope you mean ..misusing the library to force asynchronous communications..

Let's just leave the sync/async for now, as the
Code: Pascal  [Select][+][-]
  1. program test1;
  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. begin
  10.   Sock := TLUdp.Create(nil);
  11.   Sock.listen(1234);
  12.   repeat
  13.     Sock.CallAction;
  14.     if Sock.GetMessage(tmp) > 0 then
  15.       writeln(tmp);
  16.     sleep(100);
  17.   until False;
  18. end.
works fine even if there is no messages. I just tried it and it works (at least in the testing; if any problem arrives I'll let you know).

Quote
Did you look at the example ludp.pp in \config\onlinepackagemanager\packages\lnet\examples\console\ludp ??
It has a complete server/client udp example with a TLUDPTest class.
Yes, but I find it "difficult" because of the classes. Your latest example seems quite easier to understand and use (and more compact)

Side question:

as this works (even if it might have problems that I don't see in this stage of the testing):
Code: Pascal  [Select][+][-]
  1. rogram pointer_test;
  2.  
  3. var
  4.         p: pointer;
  5.  
  6. procedure a;
  7.  
  8. var
  9.         x:uint64;
  10. begin
  11.         x:=5;
  12.         p:=@x;
  13. end;
  14.  
  15. begin
  16.         a;
  17.  
  18.         writeln( uint64(p^));
  19.         readln;
  20.  
  21. end.  

this doesn't:

Code: Pascal  [Select][+][-]
  1. program multi_1;
  2. uses
  3.         SysUtils, crt, lnet;
  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. end;
  18.  
  19. begin
  20.  
  21.     connect(1234);
  22.  
  23.     repeat
  24.         pSock^.CallAction;
  25.         pSock^.GetMessage(tmp);
  26.         writeln(tmp + ' ' + pSock^.host);
  27.         sleep(500);
  28.     until False;
  29. end.

Also, I tried various ways to get the host but no success (it can be implemented inside the meagges)
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 04, 2022, 10:32:20 pm
Quote
Did you look at the example ludp.pp in \config\onlinepackagemanager\packages\lnet\examples\console\ludp ??
It has a complete server/client udp example with a TLUDPTest class.
Yes, but I find it "difficult" because of the classes. Your latest example seems quite easier to understand and use (and more compact)
As your programs get more advanced you eventually will need to go to procedures and classes.

as this works (even if it might have problems that I don't see in this stage of the testing):
Your first example works but is very dangerous. You have a pointer to some variable that doesn't exist anymore and can get overwritten at any time.

You second example has that same problem that the sock variable is local and is overwritten once you exit the procedure.
So you shouldn't use pointer p anymore.

It's better to declare sock as global variable in this case.
(or in case of a class you can define it as local class variable/property)

Also, I tried various ways to get the host but no success (it can be implemented inside the meagges)
Isn't the ip address of the sender in aSocket.PeerAddress in the OnReceive event?

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.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 04, 2022, 10:56:43 pm
Quote
Isn't the ip address of the sender in aSocket.PeerAddress in the OnReceive event?
I was trying to add it in your first of the examples.

I stumbled uppon it but couldn't find any reference of the lifetime of local variables for pascal (missed it?) but for other languages (they gone as the function ends?). In the pointer test this *seems* to not be the case; even adding sleep it gives output. The solution is obvious as you said, but less compact/neat (thats what I was trying to avoid). Is there any "control" over lifetime?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 04, 2022, 11:08:07 pm
In the pointer test this *seems* to not be the case; even adding sleep it gives output.
I can guarantee that this will go wrong at some point.
And so it did in your second example with sock  :D
With just one integer as variable it might go ok for one procedure but if your program gets more complex it WILL definitely go wrong.

The solution is obvious as you said, but less compact/neat (thats what I was trying to avoid). Is there any "control" over lifetime?
No. If you define a local variable... that's just what it is... local. You shouldn't access it outside of that procedure.

The "control" you have over the lifetime is if you make the variable global :)
Why do you think it is less neat? You also already have a pointer p which you defined global. Why not just define Sock: TLUDP global instead of the pointer p???

BTW. TLUDP is already a class. So any variable Sock: TLUDP is already a pointer. What you are doing with psock: ^TLUDP is creating a pointer to a pointer (class variable). Really not needed and inefficient.

Sock doesn't take any more memory than psock does.

So this would work just fine:

Code: Pascal  [Select][+][-]
  1. program multi_1;
  2.  
  3. uses
  4.   SysUtils, crt, lnet;
  5.  
  6. var
  7.   tmp: string;
  8.   Sock: TLUDP;
  9.  
  10.   procedure connect(port: integer);
  11.   begin
  12.     Sock := TLUdp.Create(nil);
  13.     Sock.listen(port);
  14.   end;
  15.  
  16. begin
  17.   connect(1234);
  18.   repeat
  19.     Sock.CallAction;
  20.     Sock.GetMessage(tmp);
  21.     writeln(tmp + ' ' + Sock.host);
  22.     sleep(500);
  23.   until False;
  24. end.

You can also do something like this:
Code: Pascal  [Select][+][-]
  1. program multi_1;
  2.  
  3. uses
  4.   SysUtils, crt, lnet;
  5.  
  6.   function CreateSockAndConnect(port: integer): TLUDP;
  7.   var
  8.     localSock: TLUDP;
  9.   begin
  10.     localSock := TLUdp.Create(nil);
  11.     localSock.listen(port);
  12.     Result := localSock;
  13.   end;
  14.  
  15. var
  16.   Sock: TLUDP;
  17.   tmp: string;
  18.  
  19. begin
  20.   Sock := CreateSockAndConnect(1234);
  21.   repeat
  22.     Sock.CallAction;
  23.     Sock.GetMessage(tmp);
  24.     writeln(tmp + ' ' + Sock.host);
  25.     sleep(500);
  26.   until False;
  27. end.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 04, 2022, 11:17:21 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl 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
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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 (https://castle-engine.io/modern_pascal_introduction.html)
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus 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?

Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus 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!
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus 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?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 07, 2022, 11:59:54 pm
it's not working.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus 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).
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk 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.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 08, 2022, 08:24:01 pm
With sleep(1) the program acts like having sleep(500) for example
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 08, 2022, 08:29:00 pm
With sleep(1) the program acts like having sleep(500) for example
How fast is the sender sending?

And if there (in the sender) is a same loop of receiving and sending it could be that they are waiting on each other

In that case you need to show both sender and receiver code.

(And at some point it becomes better to switch to event handling or threads.)
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 08, 2022, 08:43:48 pm
With sleep(0) or no sleep at all, it is very very very fast. Insert even the lowest possible, sleep(1), the program runs very very very slow.  %)
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 08, 2022, 08:51:21 pm
Code: Pascal  [Select][+][-]
  1. begin
  2.         connectr(1234);
  3.         repeat
  4.                 pSock.CallAction;
  5.                 pSock.GetMessage(buff);
  6.             if buff <> '' then begin
  7.                 if {(i mod 100 = 0)} true then writeln(buff,' ',pSock.Socks[0].PeerAddress);
  8.                         connects(pSock.Socks[0].PeerAddress, 1234);
  9.                     psock2.sendmessage(msg+' pong'); //needed here too, else the sender is not geting reply
  10.             end;
  11.                 delay(1);
  12.                 until buff <> '';
  13.  
  14.                 repeat
  15.                 pSock.CallAction;
  16.                 pSock.GetMessage(buff);
  17.             if buff <> '' then begin
  18.                 if {(i mod 100 = 0)} true then writeln(buff,' ',pSock.Socks[0].PeerAddress);
  19.                         //connects(pSock.Socks[0].PeerAddress, 1234);
  20.                     inc(i);
  21.                                 msg:=inttostr(i);
  22.                                 psock2.sendmessage(msg+' pong');
  23.             end;
  24.                 delay(1);
  25.                 until keypressed=true;
  26.     end;
As you said, connects once fixed the 16282 problem! :D
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 08, 2022, 08:59:23 pm
Quote
In that case you need to show both sender and receiver code.
the program is both sender/receiver.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 08, 2022, 11:00:22 pm
For me there is a difference between no delay, delay(1) and delay(500).

But the whole thing is really iffy (unstable).
If one package is missed, the whole thing stops.
(you only send a first ping from the sender but wait until you get a response pong to send the next pong to the receiver).

That's the downside of synchronous programming (what you are doing now).
If you would use asynchonous, things could be handled differently.
(I don't know if they would become faster though).

Here is a version with events OnReceive.
BTW, you can just use the same aSocket in OnReceive to send a message back to that same host.
So there is no need to open a second socket for listening and sending.

(I used GetHostIP from lcommon to get the IP. For me it's giving the wrong IP because I have multiple virtual adapters. You code for getlocalip also gave the wrong IP)

Ultimately the sender would send out a broadcast over the entire internal network and any listener could latch on and begin playing  :D )
But that's for later.

Code: Pascal  [Select][+][-]
  1. program pingpong;
  2.  
  3. uses
  4.   SysUtils,
  5.   lnet, lnetbase, lcommon,
  6.   crt, Classes, StreamIO, Windows;
  7.  
  8. var
  9.   Sock: TLUDP;
  10.   i: integer = 0;
  11.   k: integer;
  12.  
  13. type
  14.   TConsoleOutputStream = class(TStream)
  15.     function Write(const Buffer; Count: longint): longint; override;
  16.   end;
  17.  
  18.   function TConsoleOutputStream.Write(const Buffer; Count: longint): longint;
  19.   var
  20.     charcount: longword = 0;
  21.   begin
  22.     WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), @Buffer, Count, charcount, nil);
  23.     Result := charcount;
  24.   end;
  25.  
  26. type
  27.   TMyDummy = class
  28.     class procedure OnReceive(aSocket: TLSocket);
  29.   end;
  30.  
  31.   class procedure TMyDummy.OnReceive(aSocket: TLSocket);
  32.   var
  33.     tmp: string;
  34.   begin
  35.     if aSocket.GetMessage(tmp) > 0 then
  36.     begin
  37.       writeln(tmp + ' from ' + aSocket.PeerAddress);
  38.       Inc(i);
  39.       tmp := IntToStr(i);
  40.       if k = 1 then
  41.         aSocket.sendmessage(tmp + ' ping')
  42.       else
  43.         aSocket.sendmessage(tmp + ' pong');
  44.     end;
  45.   end;
  46.  
  47. begin
  48.   AssignStream(Output, TConsoleOutputStream.Create);
  49.   Rewrite(Output);
  50.   crt.WindMaxY := 9999;
  51.   i := 0;
  52.  
  53.   writeln('ip: ', GetHostIP(''));
  54.   Write('1 = send or 2 = listen? ');
  55.   readln(k);
  56.  
  57.   if k = 1 then
  58.   begin
  59.     Sock := TLUdp.Create(nil);
  60.     Sock.Connect('192.168.2.11', 1234); // <-- change the receiver IP here once
  61.     Sock.OnReceive := @TMyDummy.OnReceive;
  62.     Sock.sendmessage('ping');
  63.   end
  64.   else
  65.   begin
  66.     Sock := TLUdp.Create(nil);
  67.     Sock.Listen(1234);
  68.     Sock.OnReceive := @TMyDummy.OnReceive;
  69.   end;
  70.  
  71.   repeat
  72.     Sock.CallAction;
  73.     delay(0);
  74.   until keypressed = True;
  75.  
  76.   writeln('press enter to quit');
  77.   readln;
  78. end.

No delay, delay(0), delay(1) and delay(500) all give me increasing slower flow (which is correct).
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 08, 2022, 11:08:53 pm
After searching and testing, the "slowness" when using sleep(1) seems to be another problem unrelated to this thread, as it is common across other programs too. Even using epik timer .SystemSleep(1) the cpu usage is almost zero (note that the testing is done on vms having one cpu core, so no division per cpu cores/treads)

@rvk, you posted at the time I was writing this. Give me some time to process your info. But again, using my example (with all the flaws) without delay is pretty damn fast! Inserting the lowest possible delay it doesn't give me, for example, 90% cpu usage; it gets directly to 1% (cannot/don't-need-to meassure).
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 11:47:11 am
There were so many threads about this that I feel confident in saying that Sleep is probably the most misunderstood function in the whole RTL.

Sleep(n) does not mean "sleep n milliseconds" it means "sleep at least n milliseconds". It basically tells the scheduler, take me of the CPU and don't reschedule me for at least this amount of time. The thing is, the scheduler is slow, really slow, and takes at least like 30 millis to reschedule. So if you write Slee(1) there is practically no difference to writing Sleep(30) (more like Sleep(50) or even more). So if your program has a loop that takes only a couple of millis to execute, and then there is a Sleep(1), the amount of time it goes to sleep will be orders of magnitude greater than your execution time, resulting in an extremely low CPU usage.

The special case here is Sleep(0) because this means "Sleep at least 0 milliseconds", which is interpreted by the OS as a yield, i.e. "if there are other processes waiting to get CPU time, give it to them, otherwise let me continue". So what happens here is that if there are no other processes waiting, you won't get of the CPU and therefore stay at 100% usage, it just won't block the CPU if there are other processes that need it more. So you will fully utilize your CPU but not monopolize it, if that makes sense.

Also note that if you need to be reactive within less that 30-50 milliseconds, you cannot sleep, simple as that. You can however just use blocking socket calls, as they are build to exactly do that: if nothing has arrived, don't use the CPU and as soon as something arrives wake up the process and handle it
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 09, 2022, 03:07:38 pm
Sleep(n) does not mean "sleep n milliseconds" it means "sleep at least n milliseconds". It basically tells the scheduler, take me of the CPU and don't reschedule me for at least this amount of time.
Correct.

The thing is, the scheduler is slow, really slow, and takes at least like 30 millis to reschedule.
It's not about the scheduler being slow (it isn't), it's about what else is happening in the system. 

So if you write Slee(1) there is practically no difference to writing Sleep(30) (more like Sleep(50) or even more).
That is not the case at all.  There is a _big_ difference between Sleep(1), Sleep(30) and Sleep(50).  This is really easy to test.

So if your program has a loop that takes only a couple of millis to execute, and then there is a Sleep(1), the amount of time it goes to sleep will be orders of magnitude greater than your execution time, resulting in an extremely low CPU usage.
It will be greater, usually about 30% but, definitely _not_ "orders of magnitue greater".

The special case here is Sleep(0) because this means "Sleep at least 0 milliseconds", which is interpreted by the OS as a yield, i.e. "if there are other processes waiting to get CPU time, give it to them, otherwise let me continue".
That's what the documentation says but, the reality is very different.  Easiest way for a process to hog the CPU is to be in a loop of Sleep(0) and, suddenly there no other processes in the system that have any work to do.  Sleep(0) is something that should _never_ be used.  The documentation has been wrong since the days of NT4 and it's quite likely still wrong for Win11 (It's factually testable to be wrong up to and including Win7 SP1).

So what happens here is that if there are no other processes waiting, you won't get of the CPU and therefore stay at 100% usage,
and that happens _even_ if there are other processes waiting.  Easiest way to mess Windows up is to have as many threads as there are cores running high priority sleep(0) loops.  Don't take my word for it, _try it_!!.


Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 04:21:57 pm
It will be greater, usually about 30% but, definitely _not_ "orders of magnitue greater".
Wrong!
Code: Pascal  [Select][+][-]
  1. program sleeptimetest;
  2.  
  3. {$Mode ObjFPC}{$H+}
  4.  
  5. uses
  6.   sysUtils;
  7.  
  8. procedure Spin(time: QWord);
  9. var
  10.   startTime: QWord;
  11. begin
  12.   startTime := GetTickCount64;
  13.   while GetTickCount64 - startTime < time do;
  14. end;
  15.  
  16. var
  17.   startTime: QWord;
  18. begin
  19.   startTime := GetTickCount64;
  20.   Spin(2);
  21.   sleep(1);
  22.   Writeln('Time: ', GetTickCount64 - startTime, ' ms');
  23. end.
Workload of 2 milliseconds, total time measured on my machine 32 milliseconds. It's a factor of 16, not 1.3. And any factor > 10 are by definition orders of magnitude.

That's what the documentation says but, the reality is very different.  Easiest way for a process to hog the CPU is to be in a loop of Sleep(0) and, suddenly there no other processes in the system that have any work to do.  Sleep(0) is something that should _never_ be used.  The documentation has been wrong since the days of NT4 and it's quite likely still wrong for Win11 (It's factually testable to be wrong up to and including Win7 SP1).
Wrong!
Code: Pascal  [Select][+][-]
  1. program sleeptest;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SysUtils;
  7. begin
  8.   While True do Sleep(0);
  9. end.
Running this (and pinning it to CPU nr. 3 on my machine results in 100% load on that CPU as expected. Running it again and also pinning this to the same CPU, now both take 50% of the CPU, so sharing it equally.
Introducing a new process that does not use sleep(0):
Code: Pascal  [Select][+][-]
  1. program fullcpuutilization;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SysUtils;
  7. begin
  8.   While True do;
  9. end.
And pinning it to the same CPU results in this process taking 100% of theCPU time and the sleep processes above getting near 0% of that CPU time.

It behaves exactly as I described above, when there is no competition, it will utilize the full cpu, if there is competition it will yield time to it with two processes yielding all the time results in 50% for each, and with one process that doesn't yield and always takes the full timeslots, it will completely drown the sleeping processes.


Easiest way to mess Windows up is to have as many threads as there are cores running high priority sleep(0) loops.
No one was talking about high priority processes, but just for fun, i set the priority of one of the sleep processes to high, and guess what still 0% cpu utlilization. You are just plainly wrong.

Don't take my word for it, _try it_!!
I don't take your word for it, I know that you are wrong, I did try it, and it shows exactly what I said.

We had this same discussion last time, you were wrong then as you are wrong now. The simple 10 line programs show this without any doubt
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 09, 2022, 04:35:52 pm
  startTime := GetTickCount64;
That's how Aristotle concluded that the heavier an object is the faster it falls, dropping a rock and a feather.

here is a hint:  you really think that the tick count gets updated every CPU clock tick ?  (just in case, the answer is _no_)

Here is a piece of advice for anyone who's reading: don't _ever_ use Sleep(0). Sleep(n) will usually be reasonably close to the specified n, _usually_ within 30% (and that's only for small "n"s for larger "n"s it will be much more accurate) on a system which is running smoothly but, could be significantly more than that on a system which is not running smoothly.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 04:51:21 pm
you really think that the tick count gets updated every CPU clock tick ?  (just in case, the answer is _no_)
No but it is accurate enough in the range of several milliseconds. But sure, let's use a more accurate clock:
Code: Pascal  [Select][+][-]
  1. program sleeptimetest;
  2.  
  3. {$Mode ObjFPC}{$H+}
  4.  
  5. uses
  6.   sysUtils, windows;
  7.  
  8. var
  9.   freq: Int64;
  10.  
  11. procedure Spin(time: QWord);
  12. var
  13.   startTime, EndTime: Int64;
  14. begin
  15.   QueryPerformanceCounter(startTime);
  16.   endTime := startTime;
  17.   while (endTime - startTime) / freq * 1000 < time do
  18.     QueryPerformanceCounter(endTime);
  19. end;
  20.  
  21. var
  22.   startTime, endTime: Int64;
  23. begin
  24.   QueryPerformanceFrequency(freq);
  25.   QueryPerformanceCounter(startTime);
  26.   Spin(2);
  27.   sleep(1);
  28.   QueryPerformanceCounter(endTime);
  29.   Writeln('Time: ', round((endTime - startTime) / freq * 1000), ' ms');
  30. end.
18 milliseconds, factor of 9, still far away from 30% and around an order of magnitude.

Look I'm still right and you are still wrong...

Here is a piece of advice for anyone who's reading
Written by the person who was provably wrong about everything so far...
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 09, 2022, 04:56:25 pm
18 milliseconds, factor of 9, still far away from 30% and around an order of magnitude.
I see you like to measure things using a rubber-band,  got to admit, good method to get whatever number you want.

You should read this: https://forum.lazarus.freepascal.org/index.php/topic,49585.msg374611.html#msg374611

Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 05:48:37 pm
Ok here are some more statistics:
Code: Pascal  [Select][+][-]
  1. program sleeptimetest;
  2.  
  3. {$Mode ObjFPC}{$H+}
  4.  
  5. uses
  6.   sysUtils, windows, math;
  7.  
  8. var
  9.   freq: Int64;
  10.  
  11. procedure Spin(time: QWord);
  12. var
  13.   startTime, EndTime: Int64;
  14. begin
  15.   QueryPerformanceCounter(startTime);
  16.   endTime := startTime;
  17.   while (endTime - startTime) / freq * 1000 < time do
  18.     QueryPerformanceCounter(endTime);
  19. end;
  20.  
  21. function Sleep1Test: Integer;
  22. var
  23.   startTime, endTime: Int64;
  24. begin
  25.   QueryPerformanceCounter(startTime);
  26.   Spin(2);
  27.   sleep(1);
  28.   QueryPerformanceCounter(endTime);
  29.   Result := round((endTime - startTime) / freq * 1000);
  30. end;
  31.  
  32. var
  33.   i: Integer;
  34.   sum: Integer;
  35.   startTime: Int64;
  36.   endTime: Int64;
  37.   time: integer;
  38.   mi: Integer = 9999;
  39.   ma: integer = 0;
  40. begin
  41.   QueryPerformanceFrequency(freq);
  42.   QueryPerformanceCounter(startTime);
  43.   for i := 0 to 999 do
  44.   begin
  45.     time := Sleep1Test;
  46.     mi := min(mi, time);
  47.     ma := max(ma, time);
  48.     sum += time;
  49.   end;
  50.   QueryPerformanceCounter(endTime);
  51.   WriteLn('Min: ', mi, ' Max: ', ma, ' Average: ', Round(sum / 1000), 'ms');
  52.   WriteLn('Total: ', Round((endTime - startTime) / freq * 1000));
  53. end.
Results:
Code: Text  [Select][+][-]
  1. Min: 12 Max: 18 Average: 16ms
  2. Total: 15776
So my result above of 18 was on the upper end, with an average of 16 it's just a factor of 8 not 9, but still heaps away from 30%.
As in your example you linked, I also computed the total time, which is also around 16k ms, which, considering only 2k milliseconds of this is actual workload, also a factor 8.

Also I tried to reproduce your results from your link, by replacing the call to "Sleep1Test" with "Sleep(1)", "Sleep(8 )" and "Sleep(16)", the results for the total time are 15758, 15725 and 28692
So I can't reproduce your results. So what can be easiely seen here that the scheduler is working in time units that are somewhere around 18-20ish ms, where you yield at least the rest of your timeslice, which is depending on how much of that slice you already consumed somewhere between 0 and 18 ms, and therefore you could say that the average resolution is 16ms. That does not mean that a sleep will always take at least 16 ms (see minimum above).

Also this was on my machine with a 24 (virtual) cpus and nearly no utilization. Therefore in this example the scheduler always gave the next free timeslice to the sleeping process. But that is not necessarily the case, on a system with less cpus and moderate utilization, it could be that you need to wait more than 1 timeslice, 2-3 or so, so when calling sleep, you should always assume that in the worst case it might take 50 ms or even more. The 16 ms average is the absolute best case scenario.

So the TL;DR: You where wrong, the results you showed in the link you posted are not reproducible, and what I stated earlier still holds up using your own methodology.

PS: tested on windows 10 64 bit
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 09, 2022, 06:41:27 pm
So I can't reproduce your results.
Use the little program I posted and you'll be able to reproduce the results.  It's that simple.

BTW, in a multitasking non-RTOS O/S, the best you can do is measure averages which is why the little program I posted repeats the call 1,000 times.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 06:54:00 pm
Use the little program I posted and you'll be able to reproduce the results.  It's that simple.
Using your exact code, just wrapping some QueryPerformanceCounter around to measure time:
Code: Text  [Select][+][-]
  1. ms : 1 repeat count 1000
  2. Total time: 15.761s
  3.  
  4. ms : 8 repeat count 1000
  5. Total time: 15.773s
  6.  
  7. ms : 16 repeat count 1000
  8. Total time: 28.928s
Oh look the same results as before... It's just like, you know, I know what I'm talking about

And again, we are talking about an completely underutilized system where the scheduler can assign every timeslot to the same program, this is the absolute best case result
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 09, 2022, 07:19:27 pm
just wrapping some QueryPerformanceCounter around to measure time:
Obviously, you're messing things up somewhere because you should get the same results I get.
Title: Re: cannot receive messages; udp server with lnet
Post by: Thaddy on July 09, 2022, 07:27:00 pm
Note sleep(0) is actually called yield() in other languages. A.K.A. give up time slice if others need it. It is not forced, though. That can - depending on the complexity of other pieces in an application - have a big hit on performance if after the yield slower code will be executed.
So sleep(0) is a bit nonsense in single threaded applications, but useful in muti-threaded applications.
Mind sleep(0) may yield to the OS too, so not complete nonsense, actually. But then again, most OS's do scheduling anyway.

The above is applicable for at least WINAPI. See MSDN.

Ergo: one can not time Sleep(0)..... although I wonder if it is possible to time just the context switch.
Note that Sleep(1) WILL force a context switch.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 08:09:11 pm
Obviously, you're messing things up somewhere because you should get the same results I get.
Code: Pascal  [Select][+][-]
  1. program TestSleep;
  2.  
  3.   uses
  4.     Windows
  5.     ;
  6.  
  7.   procedure SleepLoop(ms : DWORD);
  8.   const
  9.     COUNTER_LIMIT = 1000;
  10.  
  11.   var
  12.     counter : DWORD = 0;
  13.  
  14.   begin
  15.     writeln;
  16.     writeln('ms : ', ms, ' repeat count ', COUNTER_LIMIT);
  17.     for counter := 1 to COUNTER_LIMIT do
  18.     begin
  19.       Sleep(ms);
  20.     end;
  21.   end;
  22.  
  23. var
  24.   f, s, e: Int64;
  25. begin
  26.   QueryPerformanceFrequency(f);
  27.   QueryPerformanceCounter(s);
  28.   SleepLoop(1);  { use values 1, 8 and 16 }
  29.   QueryPerformanceCounter(e);
  30.   WriteLn('Total time: ', (e-s) / f:3:3, 's');
  31.   QueryPerformanceCounter(s);
  32.   SleepLoop(8);  { use values 1, 8 and 16 }
  33.   QueryPerformanceCounter(e);
  34.   WriteLn('Total time: ', (e-s) / f:3:3, 's');
  35.   QueryPerformanceCounter(s);
  36.   SleepLoop(16);  { use values 1, 8 and 16 }
  37.   QueryPerformanceCounter(e);
  38.   WriteLn('Total time: ', (e-s) / f:3:3, 's');
  39. end.    
I kept your code char by char. I'm sorry if reality doesn't conform to your expectations, maybe you are working on some ancient windows version, but these results are consistent with my experience for at least the past 10 years as well as my theoretical knowledge of the topic
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 09, 2022, 09:32:10 pm
Just fired up a Windows XP and a Windows 2000 VM.
Windows XP:
Sleep 1: 15.711s
Sleep 8: 18.734s
Sleep 16: 31.398s

Windows 2000:
Sleep 1: 16.535s
Sleep 8: 16.796s
Sleep 16: 32.265s

I granted both VMs 2 cores so the process could monopolize one core. The results are very similar to the modern Windows 10 Results.

So I'm quite confident in saying that this behavior is how the windows sheduler works since the introduction of the NT kernel
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 09, 2022, 10:51:23 pm
With sleep(0) or no sleep at all, it is very very very fast. Insert even the lowest possible, sleep(1), the program runs very very very slow.  %)
I didn't really find it very very slow   :)

Can you give an estimate in seconds how long 1000 or 10.000 ping pongs take with my last example?

Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 09, 2022, 11:29:00 pm
This thread is on fire!! :D Am I the firestarter..? :P

Anyway,
Quote
I didn't really find it very very slow   :)

Can you give an estimate in seconds how long 1000 or 10.000 ping pongs take with my last example?

Using my last example (I currently work on this "itteration" as I get the grip of it), without sleep I get 10000 ping-pongs every ~4 seconds. Using epiktimer systemsleep(1) I get  10000 every ~210 seconds.


Code: Pascal  [Select][+][-]
  1. program multi_iv;
  2. uses
  3.         winsock, SysUtils, lnet, crt, Classes, StreamIO, Windows, strutils, lcommon, epiktimer;
  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.     ET: TEpikTimer;
  14.     now: longint;
  15. type
  16.         TConsoleOutputStream = class(TStream)
  17.     function Write(const Buffer; Count: longint): longint; override;
  18. end;
  19.  
  20. function TConsoleOutputStream.Write(const Buffer; Count: longint): longint;
  21. var
  22.     charcount: longword=0;
  23. begin
  24.     WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), @Buffer, Count, charcount, nil);
  25.     Result := charcount;
  26. end;
  27.  
  28. procedure connectr(port:integer);
  29. var
  30.         Sock: TLUDP;
  31. begin
  32.         Sock := TLUdp.Create(nil);
  33.     psock:= sock;
  34.     Sock.listen(port);
  35. end;
  36.  
  37. procedure connects(addr:string; port:integer);
  38. var
  39.         Sock2: TLUDP;
  40. begin
  41.         Sock2 := TLUdp.Create(nil);
  42.     psock2:= sock2;
  43.     Sock2.connect(addr, port);
  44. end;
  45.  
  46.  
  47. begin
  48.         AssignStream(Output, TConsoleOutputStream.Create);
  49.         Rewrite(Output);
  50.     //crt.WindMaxY := 9999;
  51.     ET := TEpikTimer.Create(nil);
  52.  
  53.     myip:= GetHostIP('');
  54.     i:=0;
  55.     writeln('ip: ',myip);
  56.         write('send or listen?');
  57.         readln(k);
  58.  
  59.     if k=1 then begin
  60.         connects('1.1.1.10', 1234);
  61.         msg:='1 ping';
  62.         psock2.sendmessage(msg);
  63.     end;
  64.                                        // sock for receive, sock2 for send
  65.     begin
  66.         connectr(1234);
  67.         repeat
  68.                 pSock.CallAction;
  69.                 pSock.GetMessage(buff);
  70.             if buff <> '' then begin
  71.                 writeln(buff,' ',pSock.Socks[0].PeerAddress);
  72.                 connects(pSock.Socks[0].PeerAddress, 1234);
  73.                 psock2.sendmessage(msg+' pong'); //needed here too, else the sender is not geting reply
  74.             end;
  75.                 ET.SystemSleep(1);
  76.                 until buff <> '';
  77.  
  78.         now:= gettickcount64;
  79.                 repeat
  80.                 pSock.CallAction;
  81.                 pSock.GetMessage(buff);
  82.             if buff <> '' then begin
  83.                 if (i mod 10000 = 0) then begin
  84.                         writeln(buff,' ',pSock.Socks[0].PeerAddress,' *',uint64(gettickcount64-now));
  85.                         now:= gettickcount64;
  86.                 end;
  87.                 inc(i);
  88.                         msg:=inttostr(i);
  89.                         psock2.sendmessage(msg+' pong');
  90.             end;
  91.                 //ET.SystemSleep(1);
  92.                 until keypressed=true;
  93.     end;
  94.  
  95.     readln;
  96. end.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 12:17:50 am
Using my last example (I currently work on this "itteration" as I get the grip of it), without sleep I get 10000 ping-pongs every ~4 seconds. Using epiktimer systemsleep(1) I get  10000 every ~210 seconds.
Ok, I see what you mean.
But with your code, the 4 seconds for 10.000 ping pongs is also a lot of time without a sleep-line.
If I use my code I get this:

Without any sleep().

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
ping from 192.168.2.11 0
1000 ping from 192.168.2.11 78
2000 ping from 192.168.2.11 78
3000 ping from 192.168.2.11 78
4000 ping from 192.168.2.11 62
5000 ping from 192.168.2.11 63
6000 ping from 192.168.2.11 62
7000 ping from 192.168.2.11 79
8000 ping from 192.168.2.11 93
9000 ping from 192.168.2.11 94
10000 ping from 192.168.2.11 78
11000 ping from 192.168.2.11 78
press enter to quit

So 765ms (0,7 seconds) for 10.000 ping pongs.

That's because my version uses the events and is much more efficient with the code flow.
Your code flow synchronous and also takes a lot of time with that flow itself (including waiting of the other side before sending another package).

Doing a sleep(0) didn't make much difference

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
ping from 192.168.2.11 0
1000 ping from 192.168.2.11 78
2000 ping from 192.168.2.11 62
3000 ping from 192.168.2.11 63
4000 ping from 192.168.2.11 62
5000 ping from 192.168.2.11 78
6000 ping from 192.168.2.11 63
7000 ping from 192.168.2.11 62
8000 ping from 192.168.2.11 78
9000 ping from 192.168.2.11 63
10000 ping from 192.168.2.11 78
press enter to quit

Only when doing sleep(1) it got a lot slower.

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
ping from 192.168.2.11 0
1000 ping from 192.168.2.11 29157
2000 ping from 192.168.2.11 29375
3000 ping from 192.168.2.11 29890
4000 ping from 192.168.2.11 30094
5000 ping from 192.168.2.11 30844
6000 ping from 192.168.2.11 30750
7000 ping from 192.168.2.11 31000
8000 ping from 192.168.2.11 30984
9000 ping from 192.168.2.11 30797
10000 ping from 192.168.2.11 30734
11000 ping from 192.168.2.11 30813
press enter to quit

BTW. With my event version the CPU doesn't go over the 25% (sometimes even far less) even without any sleep-line.

I think if you really want more control over performance you would need to go with Socket or Synapse sockets in threads.

But it all depends on what you want, where you use it for and what is practical.
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 10, 2022, 12:53:13 am
I'm sorry if reality doesn't conform to your expectations, maybe you are working on some ancient windows version, but these results are consistent with my experience for at least the past 10 years as well as my theoretical knowledge of the topic
I don't think Win7 SPI qualifies as "ancient" and, it's not about my expectations, it's about how things work.  Sleep(n) is obviously not exact but, it is much more precise than what you're getting.  Neither my computer nor my version of Windows is "special" and, it works quite nicely over here.  Sleep(n) is within 30% of n.



 
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 01:11:02 am
@rvk,

trying to use your example to verify the speed difference, I cannot compile:

Sock.OnReceive := @TMyDummy.OnReceive; gives Error: Incompatible types: got "<class method type of procedure(TLSocket) of object;Register>" expected "<procedure variable type of procedure(TLSocket) of object;Register>"
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 01:13:30 am
Side question (@everyone): Is it possible to do something like a custom sleep that waits x number of cpu cycles, or do something like the idle proccess of windows, or wait for something without polling (something else consuming cpu cycles)??

(Forgive the vagueness..)
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 10, 2022, 01:32:25 am
Is it possible to do something like a custom sleep that waits x number of cpu cycles,
In user mode, Sleep(n) is the closest thing to that.

or do something like the idle proccess of windows,
The system idle process is not a real process.

or wait for something without polling (something else consuming cpu cycles)??
there sure is.  WaitForSingle/MultipleObject, allows a process to wait until an object is signaled and, no cpu is consumed during the wait.

(Forgive the vagueness..)
No problem, you're forgiven.  Your penance is two hello-worlds and 3 binary searches.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 02:00:08 am
Quote
Quote from: prodingus on Today at 01:13:30 am
Is it possible to do something like a custom sleep that waits x number of cpu cycles,
In user mode, Sleep(n) is the closest thing to that.
sleep (tries to) measure time, regardless of cpu frequency, unless I am wrong. I am not asking to pause for x amount of time, but x amount of cpu cycles (don't know if its possible though).

Quote
Quote from: prodingus on Today at 01:13:30 am
or do something like the idle proccess of windows,
The system idle process is not a real process.
I am aware that its not a real process.

Quote
Quote from: prodingus on Today at 01:13:30 am
or wait for something without polling (something else consuming cpu cycles)??
there sure is.  WaitForSingle/MultipleObject, allows a process to wait until an object is signaled and, no cpu is consumed during the wait.
Any (easy to understand) reference on this? Is this, as Warfley said, similar to blocking sockets?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 02:01:01 am
Sock.OnReceive := @TMyDummy.OnReceive; gives Error: Incompatible types: got "<class method type of procedure(TLSocket) of object;Register>" expected "<procedure variable type of procedure(TLSocket) of object;Register>"
If you use DELPHI mode you don't need to put @ before an eventname to assign it to a event-variable. In FPCObj mode yoy DO need to put @ in front of the event-proc during assignment.

You first need to examine... do you want or need DELPHI mode?
(You did put it in one of your examples, so I used it in mine and didn't put @ in front)

If you still ave mode DELPHI at the top, remove it or remove the @.

Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 10, 2022, 02:16:08 am
sleep (tries to) measure time, regardless of cpu frequency, unless I am wrong. I am not asking to pause for x amount of time, but x amount of cpu cycles (don't know if its possible though).
You're not wrong.  There is no way to pause/wait for a specifiable "x" number of CPU cycles.

Any (easy to understand) reference on this?
The MSDN documentation on it is reasonably easy to understand and there is even an example (In C of course.)

Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 02:31:32 am
Quote
f you use DELPHI mode you don't need to put @ before an eventname to assign it to a event-variable. In FPCObj mode yoy DO need to put @ in front of the event-proc during assignment.

You first need to examine... do you want or need DELPHI mode?
(You did put it in one of your examples, so I used it in mine and didn't put @ in front)

If you still ave mode DELPHI at the top, remove it or remove the @.

I had object pascal by default for the compiler option, switched to delphi and worked without edit!

I modified your program:

Code: Pascal  [Select][+][-]
  1. program pingpong;
  2.  
  3. uses
  4.   SysUtils,
  5.   lnet, lnetbase, lcommon,
  6.   crt, Classes, StreamIO, Windows;
  7.  
  8. var
  9.   Sock: TLUDP;
  10.   i: integer = 0;
  11.   [b]j: integer = 0;[/b]
  12.   k: integer;
  13.   [b]now:longint;[/b]
  14.  
  15. type
  16.   TConsoleOutputStream = class(TStream)
  17.     function Write(const Buffer; Count: longint): longint; override;
  18.   end;
  19.  
  20.   function TConsoleOutputStream.Write(const Buffer; Count: longint): longint;
  21.   var
  22.     charcount: longword = 0;
  23.   begin
  24.     WriteConsole(GetStdHandle(STD_OUTPUT_HANDLE), @Buffer, Count, charcount, nil);
  25.     Result := charcount;
  26.   end;
  27.  
  28. type
  29.   TMyDummy = class
  30.     class procedure OnReceive(aSocket: TLSocket);
  31. end;
  32. class procedure TMyDummy.OnReceive(aSocket: TLSocket);
  33. var
  34.         tmp: string;
  35. begin
  36.                 if aSocket.GetMessage(tmp) > 0 then begin
  37.            [b]inc(j);
  38.            if (j mod 10000 = 0) then begin
  39.                 writeln(tmp + ' from ' + aSocket.PeerAddress,' *',uint64(gettickcount64-now));
  40.                 now:= gettickcount64;
  41.                    end;[/b]
  42.           Inc(i);
  43.           tmp := IntToStr(i);
  44.           if k = 1 then
  45.             aSocket.sendmessage(tmp + ' ping')
  46.           else
  47.             aSocket.sendmessage(tmp + ' pong');
  48.                 end;
  49.  
  50. end;
  51.  
  52. begin
  53.   AssignStream(Output, TConsoleOutputStream.Create);
  54.   Rewrite(Output);
  55.   crt.WindMaxY := 9999;
  56.   i := 0;
  57.   [b]j:=0;[/b]
  58.  
  59.   writeln('ip: ', GetHostIP(''));
  60.   Write('1 = send or 2 = listen? ');
  61.   readln(k);
  62.  
  63.   if k = 1 then
  64.   begin
  65.     Sock := TLUdp.Create(nil);
  66.     Sock.Connect('1.1.1.10', 1234); // <-- change the receiver IP here once
  67.     Sock.OnReceive := TMyDummy.OnReceive;
  68.     Sock.sendmessage('ping');
  69.   end
  70.   else
  71.   begin
  72.     Sock := TLUdp.Create(nil);
  73.     Sock.Listen(1234);
  74.     Sock.OnReceive := TMyDummy.OnReceive;
  75.   end;
  76.  
  77.   [b]now:= gettickcount64;[/b]
  78.   repeat
  79.         Sock.CallAction;
  80.         [b]//delay(1);[/b]
  81.   until keypressed = True;
  82.  
  83.   writeln('press enter to quit');
  84.   readln;
  85. end.

it runs about the same as mine  :o

EDIT: tried to bold the changes, but didn't knew they dont work inside "code".
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 02:38:01 am
it runs about the same as mine  :o
I tried it from a VM to host on the same machine.
Did you use two separate machines?
Was your result more than 100ms per 1000?

I'll try it with two machines tomorrow.

If you used it on the same machine I'm not sure why your performance is so poor.

Ps. I did mod 1000 to show results per 1000. Not 10.000.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 02:42:08 am
I test them VM to VM in their own vnet. Have you compiled my code and run it?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 02:43:20 am
I test them VM to VM in their own vnet. Have you compiled my code and run it?
I'll try tomorrow (sleeping now  ::) )

Ps. I did mod 1000 to show results per 1000. Not 10.000
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 12:08:49 pm
Neither my computer nor my version of Windows is "special" and, it works quite nicely over here.  Sleep(n) is within 30% of n.
I don't know whats wrong with your windows 7 version, I tested it on my Windows 10 pc, and an windows xp as well as a windows 2000 vm (I don't have Win 7 lying around so I can't test that) so unless there was something very special in Win7, this seems to be the default behavior of the NT kernel since it's inception. Maybe there is something special on your version.

or wait for something without polling (something else consuming cpu cycles)??
This is what I mentioned earlier, to use blocking calls. A blocking networking call will pause the process/thread until. I don't know much about lnet so I don't know what exactly callaction does, but when you just call a recv or recvfrom on a socket, the OS will put the process to sleep until some message arrived and then wake it up and return.
If you want to wait for a message on multiple sockets, or you want a timout on the one socket, use select (https://www.man7.org/linux/man-pages/man2/poll.2.html) poll (https://www.man7.org/linux/man-pages/man2/poll.2.html) (windows WSAPoll (https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-wsapoll)) or, if available epoll (https://www.man7.org/linux/man-pages/man7/epoll.7.html).

You can also use the WaitForMultipleObjects, which is what WSAPoll is internally calling, but WSAPoll has compatibility with the berkley socket API Poll and therefore easier to write portable code.

So the flow is, use poll to wait for data, read that data, repeat. With epoll this can easiely scale to tens of thousands of sockets being handled in microseconds. Select and poll are less efficient (O(n)) and only are capable of handling a few hundred to thousand simultanious connections without massive delays
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 10, 2022, 12:22:27 pm
Neither my computer nor my version of Windows is "special" and, it works quite nicely over here.  Sleep(n) is within 30% of n.
I don't know whats wrong with your windows 7 version, I tested it on my Windows 10 pc, and an windows xp as well as a windows 2000 vm (I don't have Win 7 lying around so I can't test that) so unless there was something very special in Win7, this seems to be the default behavior of the NT kernel since it's inception. Maybe there is something special on your version.

It will depend heavily on the CPU load of the overall system, the tick quantum, the number of cores, the number of CPUs, the way the cache is disposed between CPUs and cores, and any hints the OS can glean from the chipset relating to the technology used to access physical memory (i.e. DIMM type and so on). All of those will be taken into account when the OS decides how to schedule ready and almost-ready threads.

In addition, it is not only unsafe to assume that the scheduler will behave consistently across Windows versions, but it's also unsafe to assume that two copies of Windows of the same apparent version but with a different installation history (e.g. one started off with a slightly older DVD but was then updated) will behave the same.

The fundamental rule is that unless you have a realtime OS, Sleep(n) means Sleep(n + z) where z is >= 0 but otherwise indeterminate.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 12:35:35 pm
I test them VM to VM in their own vnet. Have you compiled my code and run it?
Your code from same machine/host to same machine/host (running side by side).

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
9999 ping from 192.168.2.11 *7297
19999 ping from 192.168.2.11 *735
29999 ping from 192.168.2.11 *765
39999 ping from 192.168.2.11 *735
49999 ping from 192.168.2.11 *734
59999 ping from 192.168.2.11 *719
69999 ping from 192.168.2.11 *703
79999 ping from 192.168.2.11 *734
press enter to quit

From VM to VM

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
9999 ping from 192.168.2.80 *8766
19999 ping from 192.168.2.80 *2156
29999 ping from 192.168.2.80 *2094
39999 ping from 192.168.2.80 *1906
49999 ping from 192.168.2.80 *2141
59999 ping from 192.168.2.80 *2156
69999 ping from 192.168.2.80 *2375
79999 ping from 192.168.2.80 *2203
press enter to quit

So, infrastructure also has something to do with it.

But did you notice the CPU doesn't go beyond 25% without any delay or sleep in this code.

(Anyway... the sleep-thing is being discussed between these posts  ;) )
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 12:48:55 pm
It will depend heavily on the CPU load of the overall system, the tick quantum, the number of cores, the number of CPUs, the way the cache is disposed between CPUs and cores, and any hints the OS can glean from the chipset relating to the technology used to access physical memory (i.e. DIMM type and so on). All of those will be taken into account when the OS decides how to schedule ready and almost-ready threads.

In addition, it is not only unsafe to assume that the scheduler will behave consistently across Windows versions, but it's also unsafe to assume that two copies of Windows of the same apparent version but with a different installation history (e.g. one started off with a slightly older DVD but was then updated) will behave the same.
The scheduler is usually something that is quite stable, for example if you look at the linux kernel git, you can see that the main functionalities of the scheduler wasn't really touched in 5-15 years. And modern day schedulers all work quite similar, they divide the time in time slices of fixed length, where only the selection of the process is different. If you call sleep(n) with n>0 then you forfit the rest of your time slice, meaning that if you sleep at completely random positions in your program your sleep will on average be at least half the timeslice. In the examples above the sleep was not at random points in the program but the program was basically nothing but sleeps, so as soon as it got resheduled after just a few operations it will have gone sleeping again, so which is why the minimum sleeping time is around the size of one timeslice.

So while you are right that there are a lot of variables in the scheduling process, especially with respect for other processes, it can easiely be mitigated on a system with enough cpus such that there is at least one underutilized, as I did for both the VMs and on my machine. Also the time slice is the absolute lower bound, the scheduler will not reschedule in the same timeslice, it is not capable of doing so, therefore you can't sleep less than the remainder of your time slice, which in the examples above is pretty much guaranteed to be nearly the full amount.

You can't say how a single sleep will behave, as the minimum and maximum measures in my example above have shown, but you can make a prediction on how the scheduler will on average work when controlling for the environment as much as possible. And the fact that the scheduler works exactly the same on both a fresh windows 2000, a windows xp which I regularly use for running old games, and my windows 10, which I use daily, is a very clear indication that the predictions seem to be correct and that the core of the scheduler have not been changed since the NT kernel was introduced
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 12:51:26 pm
I test them VM to VM in their own vnet. Have you compiled my code and run it?
As a recommendation, if you want to test how networking applications behave on a real network, I can recoomend Containernet for Linux with Docker. There you can setup a number of docker containers (which will then run your application) and define networking properties between them, e.g. which bandwith, delay, jitter and packet loss should happen between them. But sadly not available for testing windows software
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 10, 2022, 01:24:56 pm
I don't know whats wrong with your windows 7 version, I tested it on my Windows 10 pc, and an windows xp as well as a windows 2000 vm (I don't have Win 7 lying around so I can't test that) so unless there was something very special in Win7, this seems to be the default behavior of the NT kernel since it's inception. Maybe there is something special on your version.
There is nothing wrong with my Windows version but, since you insisted so much, I re-ran the tests (multiple times), here are my results:
Code: Text  [Select][+][-]
  1. timer&TestSleep.exe&timer         (1 ms)
  2. Timer 1 on:  6:57:58
  3.  
  4. ms : 1 repeat count 1000
  5. Timer 1 off:  6:57:59  Elapsed: 0:00:01.02
  6.  
  7. timer&TestSleep.exe&timer         (8 ms)
  8. Timer 1 on:  6:58:12
  9.  
  10. ms : 8 repeat count 1000
  11. Timer 1 off:  6:58:20  Elapsed: 0:00:08.01
  12.  
  13. timer&TestSleep.exe&timer         (16 ms)
  14. Timer 1 on:  6:58:34
  15.  
  16. ms : 16 repeat count 1000
  17. Timer 1 off:  6:58:50  Elapsed: 0:00:16.02
  18.  
  19. timer&TestSleep.exe&timer         (1 ms)
  20. Timer 1 on:  7:00:21
  21.  
  22. ms : 1 repeat count 1000
  23. Timer 1 off:  7:00:22  Elapsed: 0:00:01.01
  24.  
  25. timer&TestSleep.exe&timer         (8 ms)
  26. Timer 1 on:  7:01:14
  27.  
  28. ms : 8 repeat count 1000
  29. Timer 1 off:  7:01:22  Elapsed: 0:00:08.01
  30.  
  31. timer&TestSleep.exe&timer         (1 ms)
  32. Timer 1 on:  7:03:22
  33.  
  34. ms : 1 repeat count 1000
  35. Timer 1 off:  7:03:23  Elapsed: 0:00:01.02
  36.  
As you can see in the above, the times are within 2% of the sleep time.  I also ran the tests in a Win7 VM and the results were erratic and closer to what you've mentioned, as a result, I rebooted that VM and re-ran the tests and got results that were almost identical to the above but a bit slower, likely due to the fact that the test was done in a VM but, still well within the 20% variation I mentioned.  Looks like some things get "strange" sometimes in a VM. I've noticed that in other things too.  Every few weeks I have to reboot the Win7 VM I use for development because I do notice it has slowed down (I don't know why and since the fix is easy, reboot, I've never bothered to investigate the reason.)

As you can see, I repeated the 1 ms test (twice in the above) multiple times to see if there would be any variation and, there wasn't.  All the tests finished within 2 to 5% of 1 ms.

If you are not getting the results I am getting then, the conclusion is, there is something not quite right in your Windows configuration. I assure you, there is absolutely nothing unusual in my Win7 SP1 installation.  It's as plain vanilla as it gets.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 02:02:17 pm
If you are not getting the results I am getting then, the conclusion is, there is something not quite right in your Windows configuration. I assure you, there is absolutely nothing unusual in my Win7 SP1 installation.  It's as plain vanilla as it gets.
Just tested it on my laptop, which is the most freshly installed windows I have (as I usually only use linux on it), I never changed any os level configuration on this. Same results. I also reran the vm tests multiple times after restarting the vms

So I've now conducted tests on 4 machines, 2 virtual, two physical, accross 4 different windows versions, all report the same results. It cannot be my configuration that is wrong, I always get the same consistent results accross all configurations, and they are also consistent with theory.
Maybe it is just that windows 7 is different with scheduling, but this cannot be a wrong configuration or vm weirdness, I get consistent results across 4 different configurations, 2 virtual 2 physical on different hardware, all using different operating systems and configurations. I measured the time both using queryperformancecounter, and also Measure-Command (as we are talking about measurements in the tens of seconds), I get the same results everywhere.
If I have ever seen a consistent experiment than this is it. There is no doubt that this is not a configuration issue or VM issue on my end.
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 10, 2022, 02:39:52 pm
So I've now conducted tests on 4 machines, 2 virtual, two physical, accross 4 different windows versions, all report the same results. It cannot be my configuration that is wrong, I always get the same consistent results accross all configurations, and they are also consistent with theory.
I wouldn't be so sure of that.  Sleep's behavior is something I've been testing from Windows version to Windows version since, at least, Win2000 and, it's been very consistent.  The only times I get inconsistencies is when Windows is running in a VM and, after rebooting, Sleep works as expected (and as it should, I might add.)

I don't know why you're getting weird numbers but, the results should be very close to those I posted and, if they aren't then, something is wrong with the Windows configuration (unless it's in a VM.  As I've previously stated, I've seen strange results in VMs but, a reboot brings them back to what they should be.)

On the other hand, I just tried the test in a Win 10 VM (which has been up for weeks) and, I got "weird" results like yours but, I'm not rebooting that thing.  Every time I reboot it, the Windows defender spends half a day scanning for viruses, which is rather annoying and, the overhead and disk access slows down the other VMs I actually use.  (I only use that Win10 VM for testing, not for development, IOW, I don't really care if it's screwed up, as long as I can use it for testing it's good enough and, I only care that the program loads, runs and the results are correct, fast or slow, I couldn't care less about that on Win10)

Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 02:47:28 pm
I also spun up a Windows 7 VM on both my Desktop and my Laptop, same results.

So to recap, I got on 5 setups, two native on different hardware, 3 virtual, repeating multiple times (with reboots) the exact same results, not a single time the results you got. This must be a problem on your device.
I can't explain your results, in fact I have never seen such results anywhere to this day. My results are so consistent there is no way this is some configuration issue, so it must be a you problem.

So I will leave it at that. I don't know whats the issue at your end, but with so many different configurations giving the same result, there is no way that this isn't the "correct"/intendet behavior
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 07:42:58 pm
I test them VM to VM in their own vnet. Have you compiled my code and run it?
Your code from same machine/host to same machine/host (running side by side).

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
9999 ping from 192.168.2.11 *7297
19999 ping from 192.168.2.11 *735
29999 ping from 192.168.2.11 *765
39999 ping from 192.168.2.11 *735
49999 ping from 192.168.2.11 *734
59999 ping from 192.168.2.11 *719
69999 ping from 192.168.2.11 *703
79999 ping from 192.168.2.11 *734
press enter to quit

From VM to VM

Quote
ip: 172.18.144.1
1 = send or 2 = listen? 2
9999 ping from 192.168.2.80 *8766
19999 ping from 192.168.2.80 *2156
29999 ping from 192.168.2.80 *2094
39999 ping from 192.168.2.80 *1906
49999 ping from 192.168.2.80 *2141
59999 ping from 192.168.2.80 *2156
69999 ping from 192.168.2.80 *2375
79999 ping from 192.168.2.80 *2203
press enter to quit

So, infrastructure also has something to do with it.

But did you notice the CPU doesn't go beyond 25% without any delay or sleep in this code.

(Anyway... the sleep-thing is being discussed between these posts  ;) )

I rerun mine and your version in a laptop too. Same VM setups, exact copies (only one thread/cpu). That 25% of yours, are you on a quad core/thread? Yours vs mine results the same speed both in laptop and pc (PC ryzen, laptop 2nd gen i5).

The interesting part is (without using sleep at all) I get full cpu utilization on both systems and same speed results (10.000 ping-pongs per ~ 4secs). Which means that something funny is happening, backed by your results; if the vms are causing lattency/delay/"slowness", and the getmessage "halts" the cpu untill a message has arrived in the buffer, and cpu/thread is 100% even in a high-end machine, then does-not-compute!!! %)

Also, swith sleep(1) on yours and mine I get the same sluglish results, 100 ping-pongs per ~ 2secs, and almost no cpu utilization.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 08:01:33 pm
So, infrastructure also has something to do with it.
Don't assume that connections on the same machine work the same as connections accross machines (or to be more precise on the same network interface vs different network interfaces). Basically when you send data from one network interface to itself, there is no reason for the OS to do all the networking, all the wrapping in IP packages and sending it across the NIC is not necessary. So it can easiely be that the OS will simply put the messages directly into the buffer of the target application, circumventing the whole network interface.
This is a common problem when trying to use wireshark or similar programs to sniff data over the loopback address without workarounds (on windows, on linux loopback goes through the network interface and can be sniffed easiely).

So different behavior is expected.

And about the CPU utlization with sleep(1), I know the sleep discussion went a bit of the rails, but the core message what I wanted to get across is, sleep(1) sleeps several MS, so if your your workload between the sleeps is very short (and handling a message is pretty much no effort at all), then the ratio between workload and sleeptime, which is the CPU load, will be extremely low. Try rather than sleeping every iteration, only sleep after like 1000 iterations. This way you can balance the sleeping against the worktime
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 08:06:17 pm
On my previous message (perhaps I was faster writing than thinking), does the full cpu/tread utilization beed caused by the repeating of pSock.CallAction ?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 08:06:58 pm
So, infrastructure also has something to do with it.
Don't assume that connections on the same machine work the same as connections accross machines (or to be more precise on the same network interface vs different network interfaces).
OS is also part of the infrastructure.

I just meant to say that the slowness isn't only caused by the sleep.
There is much more in play here.

Also... You have one side sending a message and the other side waiting for it. This isn't done asynchronous so the waiting element on both sides could be in play too. Sleep could double or triple because of that (sender sleeps before receiving an answer and answer back (and that times two).

Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 08:09:33 pm
Quote
Don't assume that connections on the same machine work the same as connections accross machines (or to be more precise on the same network interface vs different network interfaces). Basically when you send data from one network interface to itself, there is no reason for the OS to do all the networking, all the wrapping in IP packages and sending it across the NIC is not necessary. So it can easiely be that the OS will simply put the messages directly into the buffer of the target application, circumventing the whole network interface.

I was under the assumption that vms with their own vnet were going to have the lowest latency.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 08:09:56 pm
On my previous message (perhaps I was faster writing than thinking), does the full cpu/tread utilization beed caused by the repeating of pSock.CallAction ?
It could. I'm not sure how that function looks at the moment but if it just checks for communication and doesn't yield processing power, then your program just takes all the cpu (it would effectively be a
Code: Pascal  [Select][+][-]
  1. Repeat
  2.   // Do nothing
  3. Until false;
  4.  
Which is really OS unfriendly.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 08:26:45 pm
I was under the assuption that vms with their own vnet were going to have the lowest latency.
How a VM works is basically it provides a virtual network interface on the vm, when the VM writes to that virtual interface, the packets will be read out by the virtualisation software, and, in this configuration, be transmitted to the virtual network interface that the virtualisation software creates on the host. From there the messages are handled by the OS, which sees the target being another virtual network interface, the one of the second VM, and send them to it, which will trigger the virtualization software to take these packages and put them into the virtual network interface on the second virtual machine, where you can read them out.
This has a low latency because there is no real wire, but there still is a lot of moving memory around involved, this cannot be optimised further because the OS does not know whats behind the virtual interface provided by the VM.

When you send a message from a network interface to itself, i.e. two processes communicate with each other, the OS can see that, and directly let those communicate without actually involving the network interface. It saves a few steps in the process. Also at each of these stages package loss can happen if the buffers overflow because the forwarding is not fast enough.

So long story short, VMs add a lot of overhead to the system. Not as much as a real wire, but more than just two processes communicating with each other.

About the CPU utilization issues, I edited my last post with some more stuff about it, but you where so much faster in posting that you might not have seen it:
Quote
And about the CPU utlization with sleep(1), I know the sleep discussion went a bit of the rails, but the core message what I wanted to get across is, sleep(1) sleeps several MS, so if your your workload between the sleeps is very short (and handling a message is pretty much no effort at all), then the ratio between workload and sleeptime, which is the CPU load, will be extremely low. Try rather than sleeping every iteration, only sleep after like 1000 iterations. This way you can balance the sleeping against the worktime

I don't know much about lnet, but I guess that internally it will use blocking calls. So the reason why the CPU load is at 100% is, that every time it is called there is data in the buffer. Therefore every time it calls recv, it will read out that data from the buffer without having to wait, so you get 100% cpu load. The question is, if you slow down the sender, does the CPU load get down? If so, the reason you have 100% CPU load is simply because you get so much data that this is the fastest you can read the data. If you then slow down the receiver through sleep, you will simply loose most of your message sent. So you better controll this on sender side not at receiver side.
But if you want to slow down on receiver side, simply don't sleep every turn, but have a few turns and sleep then. You could use time measurements to make sure that for every 50 milliseconds of receiving you sleep another 20 ms, this way your CPU utilization will not be above 80%
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 08:52:23 pm
Quote
The question is, if you slow down the sender, does the CPU load get down?
Running the "sender" on the first vm with sleep(1) and the "receiver" at the other vm, the receiver is still @ 100% cpu.

Quote
About the CPU utilization issues, I edited my last post with some more stuff about it, but you where so much faster in posting that you might not have seen it:
Quote
And about the CPU utlization with sleep(1), I know the sleep discussion went a bit of the rails, but the core message what I wanted to get across is, sleep(1) sleeps several MS, so if your your workload between the sleeps is very short (and handling a message is pretty much no effort at all), then the ratio between workload and sleeptime, which is the CPU load, will be extremely low. Try rather than sleeping every iteration, only sleep after like 1000 iterations. This way you can balance the sleeping against the worktime

Yeap I missed it, my bad (TMI on this thread, so little time). I never thought of running a counter to get sleep at steps, as it "adds" more program logic thus eating cpu cycles (even if negligible).

Also on the blocking sockets thing, I get the feel that this is a "wrong" way to reduce cpu usage; it's just me of cource and my personal taste when wrighting a program.

EDIT: running counter to trigger sleep also feels wrong, because its more like get-some-messages then stop, repeat.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 08:53:43 pm
Quote
I don't know much about lnet, but I guess that internally it will use blocking calls. So the reason why the CPU load is at 100% is, that every time it is called there is data in the buffer.
It seems that this is not the case.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 09:16:29 pm
I rerun mine and your version in a laptop too. Same VM setups, exact copies (only one thread/cpu). That 25% of yours, are you on a quad core/thread? Yours vs mine results the same speed both in laptop and pc (PC ryzen, laptop 2nd gen i5).
I'm on Windows 10 Pro 64 bit, an old Dell XPS8500 with Intel Core I7 3770 - 3.4 Ghz - 4 Cores - 8 Threads.

When the sender is in a VM (Hyper V, Windows 10, 1 CPU) it does reach 100%.

You can try to play with SetProcessAffinityMask and SetThreadAffinityMask but it wouldn't change the CPU immediately. It would make the rest of the OS more responsive because your program would run in lower priority.

Maybe threads could help too but I haven't tried that.

It kinda depends on what you are actually after.
If you want real-time communications.... that just takes time and cpu power.

BTW. It's not only the project.exe which takes a lot of CPU. conhost.exe takes it share too (probably the network handling).
When my VM is 100% busy... project.exe takes about 50% and conhost 30%. Interrupts takes 15%.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 09:25:47 pm
I added a counter in order to do sleep(1) @ 1000 repeats. The first run I thougt I broke the lnet (just kidding). The results are all over the place:

the first attempt had writeln @ 10.000 repeats (just as the last code I posted) only with the new counter & sleep. I got the first 10.000 ping-pongs, then I didn't see any output for about 10+ minutes; the cpu usage was constanly @ ~ 50-65% (and yes after some time I set the affinity of the vms and the fluctuations were gone).
Then I changed the writeln to 100 ping-pongs and the results:

Code: Pascal  [Select][+][-]
  1. ip: 1.1.1.10
  2. send or listen?3
  3. 1 ping 1.1.1.1
  4. 1 ping pong 1.1.1.1 *78
  5. 100 pong 1.1.1.1 *1685
  6. 200 pong 1.1.1.1 *46
  7. 300 pong 1.1.1.1 *94
  8. 400 pong 1.1.1.1 *16
  9. 500 pong 1.1.1.1 *156
  10. 600 pong 1.1.1.1 *15
  11. 700 pong 1.1.1.1 *63
  12. 800 pong 1.1.1.1 *78
  13. 900 pong 1.1.1.1 *62
  14. 1000 pong 1.1.1.1 *78
  15. 1100 pong 1.1.1.1 *16
  16. 1200 pong 1.1.1.1 *109
  17. 1300 pong 1.1.1.1 *47
  18. 1400 pong 1.1.1.1 *93
  19. 1500 pong 1.1.1.1 *31
  20. 1600 pong 1.1.1.1 *78
  21. 1700 pong 1.1.1.1 *78
  22. 1800 pong 1.1.1.1 *110
  23. 1900 pong 1.1.1.1 *62
  24. 2000 pong 1.1.1.1 *78
  25. 2100 pong 1.1.1.1 *78
  26. 2200 pong 1.1.1.1 *47
  27. 2300 pong 1.1.1.1 *62
  28. 2400 pong 1.1.1.1 *141
  29. 2500 pong 1.1.1.1 *46
  30. 2600 pong 1.1.1.1 *3276
  31. 2700 pong 1.1.1.1 *94
  32. 2800 pong 1.1.1.1 *47
  33. 2900 pong 1.1.1.1 *46
  34. 3000 pong 1.1.1.1 *94
  35. 3100 pong 1.1.1.1 *47
  36. 3200 pong 1.1.1.1 *78
  37. 3300 pong 1.1.1.1 *2059
  38. 3400 pong 1.1.1.1 *3183
  39. 3500 pong 1.1.1.1 *2589
  40. 3600 pong 1.1.1.1 *187
  41. 3700 pong 1.1.1.1 *16
  42. 3800 pong 1.1.1.1 *78
  43. 3900 pong 1.1.1.1 *78
  44. 4000 pong 1.1.1.1 *94
  45. 4100 pong 1.1.1.1 *46
  46. 4200 pong 1.1.1.1 *78
  47. 4300 pong 1.1.1.1 *63
  48. 4400 pong 1.1.1.1 *47
  49. 4500 pong 1.1.1.1 *140
  50. 4600 pong 1.1.1.1 *4025
  51. 4700 pong 1.1.1.1 *1700
  52. 4800 pong 1.1.1.1 *1201
  53. 4900 pong 1.1.1.1 *3214
  54. 5000 pong 1.1.1.1 *1451
  55. 5100 pong 1.1.1.1 *47
  56. 5200 pong 1.1.1.1 *93
  57. 5300 pong 1.1.1.1 *31
  58. 5400 pong 1.1.1.1 *78
  59. 5500 pong 1.1.1.1 *94
  60. 5600 pong 1.1.1.1 *62
  61. 5700 pong 1.1.1.1 *63
  62. 5800 pong 1.1.1.1 *62
  63. 5900 pong 1.1.1.1 *78
  64. 6000 pong 1.1.1.1 *63
  65. 6100 pong 1.1.1.1 *62
  66. 6200 pong 1.1.1.1 *62
  67. 6300 pong 1.1.1.1 *47
  68. 6400 pong 1.1.1.1 *125
  69. 6500 pong 1.1.1.1 *1123
  70. 6600 pong 1.1.1.1 *47
  71. 6700 pong 1.1.1.1 *78
  72. 6800 pong 1.1.1.1 *499
  73. 6900 pong 1.1.1.1 *172
  74. 7000 pong 1.1.1.1 *47
  75. 7100 pong 1.1.1.1 *47
  76. 7200 pong 1.1.1.1 *62
  77. 7300 pong 1.1.1.1 *94
  78. 7400 pong 1.1.1.1 *31
  79. 7500 pong 1.1.1.1 *78
  80. 7600 pong 1.1.1.1 *47
  81. 7700 pong 1.1.1.1 *93
  82. 7800 pong 1.1.1.1 *63
  83. 7900 pong 1.1.1.1 *78
  84. 8000 pong 1.1.1.1 *124
  85. 8100 pong 1.1.1.1 *16
  86. 8200 pong 1.1.1.1 *577
  87. 8300 pong 1.1.1.1 *3495
  88. 8400 pong 1.1.1.1 *1263
  89. 8500 pong 1.1.1.1 *952
  90. 8600 pong 1.1.1.1 *31
  91. 8700 pong 1.1.1.1 *78
  92. 8800 pong 1.1.1.1 *94
  93. 8900 pong 1.1.1.1 *46
  94. 9000 pong 1.1.1.1 *110
  95. 9100 pong 1.1.1.1 *31
  96. 9200 pong 1.1.1.1 *78
  97. 9300 pong 1.1.1.1 *62
  98. 9400 pong 1.1.1.1 *63
  99. 9500 pong 1.1.1.1 *374
  100. 9600 pong 1.1.1.1 *47
  101. 9700 pong 1.1.1.1 *1029
  102. 9800 pong 1.1.1.1 *110
  103. 9900 pong 1.1.1.1 *93
  104. 10000 pong 1.1.1.1 *63
  105. 10100 pong 1.1.1.1 *15
  106. 10200 pong 1.1.1.1 *141
  107. 10300 pong 1.1.1.1 *1607
  108. 10400 pong 1.1.1.1 *1560
  109. 10500 pong 1.1.1.1 *62
  110. 10600 pong 1.1.1.1 *47
  111. 10700 pong 1.1.1.1 *62
  112. 10800 pong 1.1.1.1 *94
  113. 10900 pong 1.1.1.1 *62
  114. 11000 pong 1.1.1.1 *94
  115. 11100 pong 1.1.1.1 *47
  116. 11200 pong 1.1.1.1 *62
  117. 11300 pong 1.1.1.1 *78
  118. 11400 pong 1.1.1.1 *421
  119. 11500 pong 1.1.1.1 *31
  120. 11600 pong 1.1.1.1 *63
  121. 11700 pong 1.1.1.1 *125
  122. 11800 pong 1.1.1.1 *78
  123. 11900 pong 1.1.1.1 *15
  124. 12000 pong 1.1.1.1 *94
  125. 12100 pong 1.1.1.1 *47
  126. 12200 pong 1.1.1.1 *78
  127. 12300 pong 1.1.1.1 *62
  128. 12400 pong 1.1.1.1 *62
  129. 12500 pong 1.1.1.1 *16
  130. 12600 pong 1.1.1.1 *62
  131. 12700 pong 1.1.1.1 *47
  132. 12800 pong 1.1.1.1 *1092

It is random when and if the program woud "hang"; actually I thing the "hang" is accumulation of sleep(1) from both sides.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 09:27:18 pm
Also on the blocking sockets thing, I get the feel that this is a "wrong" way to reduce cpu usage; it's just me of cource and my personal taste when wrighting a program.
It is the only correct way if you don't want to be at 100% CPU load. There are two ways to use sockets, either blocking or nonblocking. Blocking sockets will reduce CPU usage as much as possible, as every time there is no data, it will sleep until data is there. When you are doing a sleep loop where you check if data is there and if not go to sleep, you basically build the same thing just with extra steps.

Non blocking sockets are only required if you want to do other things while waiting for the socket on the same thread. This is a highly specialized use-case for when you need to build single threaded applications but still have asynchronous I/O. Usually whenever someone talks about non blocking sockets, in most cases what they really want to use is select/poll/epoll. True asynchronous programming is used rather infrequently, and most people just want a simple timeout or handle multiple sockets, or want to check if a message they are awaiting is already there. In all of these cases select/poll/epoll will do the trick, while still reducing cpu load by blocking.

PS: as a little rant on the side, I must say LNet is absolutely terrible, there is no documentation, the method names give absolutely no indication what they are doing (e.g. CallAction, this doesn't call any actions, it handles events, why isn't it named HandleEventQueue or something meaningful), and from reading the code I had absolutely no idea that it is either non blocking, or threaded. You look at this code and have no idea what it does.
Also the same code you wrote using Lnet, could be writting in probably half that code using the raw socket API. So you are using a library that has throusands of lines of code, so you can write more code... I thought the L stands for lightweight...
This is something I have observed with many networking libraries that try to make low level protocols (i.e. TCP and UDP) easier, in the end they are just way more complicated than the raw socket API. This sort of design works well for high level protocols like SMTP or HTTP, but by trying to make low level protocols easier, they just made using them harder
/rant over
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 09:33:01 pm
Quote
PS: as a little rant on the side, I must say LNet is absolutely terrible, there is no documentation, the method names give absolutely no indication what they are doing (e.g. CallAction, this doesn't call any actions, it handles events, why isn't it named HandleEventQueue or something meaningful), and from reading the code I had absolutely no idea that it is either non blocking, or threaded. You look at this code and have no idea what it does.
Also the same code you wrote using Lnet, could be writting in probably half that code using the raw socket API. So you are using a library that has throusands of lines of code, so you can write more code... I thought the L stands for lightweight...
This is something I have observed with many networking libraries that try to make low level protocols (i.e. TCP and UDP) easier, in the end they are just way more complicated than the raw socket API. This sort of design works well for high level protocols like SMTP or HTTP, but by trying to make low level protocols easier, they just made using them harder
/rant over

AMEN!
https://c.tenor.com/eOXG7de_rCoAAAAd/steve-carell-thankyou.gif (https://c.tenor.com/eOXG7de_rCoAAAAd/steve-carell-thankyou.gif)
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 10, 2022, 09:44:22 pm
Quote
It is random when and if the program woud "hang"; actually I thing the "hang" is accumulation of sleep(1) from both sides.

Scratch that, I wrote again before giving a second thought: If sleep accumulation was happening, then the cpu usage would drop, but it doesn't.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 10, 2022, 10:04:22 pm
That's why I said right from the start you're better off using Socket of Synapse sockets in threads (but I haven't tested that).

And it all still depends on what you want.

I think you said you just wanted to learn and all this was theoretical.
Then you should not dwell too long on sleep and lnet but start exploring socket and threads for your example.
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 10, 2022, 10:05:27 pm
Quote
It is random when and if the program woud "hang"; actually I thing the "hang" is accumulation of sleep(1) from both sides.

Scratch that, I wrote again before giving a second thought: If sleep accumulation was happening, then the cpu usage would drop, but it doesn't.

In your test code, assign a value > 0 to the Sock.Timeout and remove sleeps. Then try again.

Code: Pascal  [Select][+][-]
  1.  ...
  2.  if k = 1 then
  3.   begin
  4.     Sock := TLUdp.Create(nil);
  5.     Sock.Connect('1.1.1.10', 1234); // <-- change the receiver IP here once
  6.     Sock.OnReceive := @TMyDummy.OnReceive;
  7.     Sock.Timeout := 50;
  8.     Sock.sendmessage('ping');
  9.   end
  10. ...
  11.  

Edit: Your test code from reply #119
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 10, 2022, 10:58:28 pm
I might again recommend you trying my PasSimpleSockets out: https://github.com/Warfley/PasSimpleSockets
It is basically just a thin layer around the default sockets API. A simple UDP server that sends ping-pongs would be:
Code: Pascal  [Select][+][-]
  1. program pingpongserver;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SimpleSockets;
  7.  
  8. var
  9.   Sock: TSocket;
  10.   Msg: TReceiveFromStringMessage;
  11. begin
  12.   Sock := UDPSocket(stDualStack);
  13.   try
  14.     // Binding to 0-IP (here in ipv6 format) binds to any address, with stDualStack both IPv4 and IPv6
  15.     Bind(Sock, '::0', 1337);
  16.     repeat
  17.       Msg := ReceiveStrFrom(Sock);
  18.       WriteLn('Ping received from ', Msg.FromAddr.Address, ':', Msg.FromPort,' message: ', Msg.Data);
  19.       SendStrTo(Sock, Msg.FromAddr, Msg.FromPort, Msg.Data + 'Pong');
  20.     until False;
  21.   finally
  22.     CloseSocket(Sock);
  23.   end;
  24.   ReadLn;
  25. end.

If you want to work non blockingly, you can use DataAvailable (internally using select):
Code: Pascal  [Select][+][-]
  1. program pingpongserver;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   SimpleSockets;
  7.  
  8. var
  9.   Sock: TSocket;
  10.   Msg: TReceiveFromStringMessage;
  11. begin
  12.   Sock := UDPSocket(stDualStack);
  13.   try
  14.     // Binding to 0-IP (here in ipv6 format) binds to any address, with stDualStack both IPv4 and IPv6
  15.     Bind(Sock, '::0', 1337);
  16.     repeat
  17.       while not DataAvailable(Sock) do
  18.          WriteLn('Waiting for Data'); // do whatever while waiting for your data
  19.       Msg := ReceiveStrFrom(Sock);
  20.       WriteLn('Ping received from ', Msg.FromAddr.Address, ':', Msg.FromPort,' message: ', Msg.Data);
  21.       SendStrTo(Sock, Msg.FromAddr, Msg.FromPort, Msg.Data + 'Pong');
  22.     until False;
  23.   finally
  24.     CloseSocket(Sock);
  25.   end;
  26.   ReadLn;
  27. end.
If you don't want 100% CPU usage, you can add a timeout to DataAvailable, which will basically say: wait until data is available or until the timeout is reached (See DataPendingTest.pas in the examples folder).

Personally I find this much easier than LNet. And if you want to make this threaded, just put that code in threads yourself.

PS: Note how this uses DualStack, meaning it is a server socket that support both IPv4 and IPv6 completely transparently, this is something that LNet can't even do
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 10, 2022, 11:08:45 pm
@Warfley
The LNet isn't so bad, actually I've checked it - the Sock.CallAction will call fpSelect() and as long there is a Sock.Timeout > 0 it will behave as expected.
Default is Sock.Timeout = 0 and because of that the CPU utilization will be 100% unless a sleep(x) added (but then everything will slow down).
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 12:31:53 am
And about the CPU utlization with sleep(1), I know the sleep discussion went a bit of the rails, but the core message what I wanted to get across is, sleep(1) sleeps several MS,
Not in a properly running Windows installation.  That statement is simply incorrect.

On a properly running Windows installation Sleep(n) will usually be very close to "n".  The exceptions are, when something isn't quite right in the Windows installation or the system is very busy. 

The Windows scheduler isn't a run of the mill thread that only gets to execute every 15ms (or whatever the thread quantum may be.) Scheduler code runs a lot more often than that.  In addition to that, when a thread is sleeping, the quantum is irrelevant because the quantum applies to threads that are running not sleeping.

In a Windows installation that is functioning as it should, the Sleep(n) measurements should be very similar to the ones I posted.

In VMs the divergence is larger but, it should still be within about 20%.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 12:35:33 am
That CallAction checks if data available isn't any better, there is still no documentation, and the name CallAction does not imply that in anyway that it does any of that.
Like how are you as someone who has never used LNet supposed to know any of that? Even if I ctrl click on the Identifier to look into CallAction, all I see is:
Code: Pascal  [Select][+][-]
  1. procedure TLUdp.CallAction;
  2. begin
  3.   if Assigned(FEventer) then
  4.     FEventer.CallAction;
  5. end;
Where FEventer.CallAction is an empty virtual method.

Also structurally LNet does not make sense, TLUDP is a TLConnection and therefore has things like  Disconnect, which does not make sense in any UDP context, and if you look into it it has a bunch of TCP only code and basically just closes the socket for UDP... Why not have a function CloseSocket for UDP instead of inheriting all the TCP code that does not apply to UDP.
I don't even see how anyone can have the audacity to call any of this lightweight, because to me carrying a bunch of TCP only code around in your UDP class is pretty much the opposite of leightweight.

I consider myself quite knowledgable about writing networking code, I've written a few networking libraries myself. But when I look at that LNet code, I don't understand what is happening.
Take indy for comparison, indy is not the gold standard for ease of understanding at all, but in indy everything at least makes sense, if you create an UDP server, you add the bindings to the IP addresses, then you set active to true and it will start serving requests until you set active to false. Indy is not perfect, but thats at least easy to understand and no ambigous "CallAction" or "Disconnect" or other things whose names make 0 sense in this context.

LNet is really terrible, probably the worst networking library I have seen until now. And the worst thing is, it is one of these libraries that tries to be "intelligent" and tries to anticipate what the programmer wants, e.g. by using non blocking calls by default, where you simply ask yourself why? Why do something that can be considered rather special (because as explained above, you usually don't need non blocking calls) by default?

But I think I ranted enough about this library.
I can just repeat, for simple things like this, I don't see the need for any library, just to use the berkley sockets api, which is already a very simple API. Maybe with a slim wrapper as I posted above, maybe not if one is comfortable in writing the helper functions directly, thats up to everyone how they please.
And for more complex stuff like when threading or other more advanced stuff is required, there are much better libraries available, as much as I like to make fun of Indy for beeing bloated, it works, is well structured and easiely understandable, and will have everything you could ever wish for, if it's thread support, SSL support, Non blocking sockets, you name it. (Even though I would also recommend to implement threading by yourself, threading is hard, so it's best to exactly know what happens when)
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 12:37:55 am
In a Windows installation that is functioning as it should, the Sleep(n) measurements should be very similar to the ones I posted.
Remind me again, on how many different machines and windows versions have you tested this? Because as far as I remember I tested 5 different configurations on different hardware, some VMs, some not and all showed the opposite of what you where claiming...

Maybe you should get some evidence before you continue talking...

And if you have a VM that shows your behavio when freshly booted (as you claim) please make a snapshot and upload it so I can run it on my machine and verify it. This should be extremly easy, because from all my tests I never came close to your results.

Also ive noticed that you never used the same code as I (which i posted here) for doing the measurements... Is it because you cant get your (wrong) results with a comparable test or do you think it is methodologically wrong? If you think the latter please let me know, otherwise, please use the same code or share your measurement code (including timing code) so we have comparable results

And if you continue talking stuff without any evidence behind it, I will start calling you what you are, a liar. At some point my good faith is over
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 01:08:11 am
@Warfley
I'm just saying that LNet is not so bad considering the OP issues in that thread, that's all. Already at post #153, I was just curious what so difficult in the UDP one may have and I found most of the time two people fight about the peculiarities of the scheduler and the purpose of the sleep function.

But the OP trouble is how to do an I/O properly and the fpSelect() is the right way for that, isn't it? It will give up on the slice and so on.

There is nothing wrong to work with non-blocking sockets as long as you do it properly. Most of the servers do it. Yes, that requires more deep knowledge, but what else doesn't requires it?
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 01:21:22 am
Quote
There is nothing wrong to work with non-blocking sockets as long as you do it properly. Most of the servers do it. Yes, that requires more deep knowledge, but what else doesn't requires it?
Usually non blocking socjets are used to serve many sockets on one thread to have more scalable server. The problem here is that non blocking polling still requires going over every socket to see if they have any data I.e. O(n). For this, at least on Linux you should rather use epoll, which is event based and therefore functions in O(1), and then use blocking calls afterwards, that said if you really need every bit performance you use epoll with a timeout of 0 (I.e. non blocking) in a loop to avoid context switchens, and also der the sockets non blocking because this optimises the usage of Pool on large buffers, but this is just necessary for extremely utilized servers. For everything else non nlocking should be enough
Only exception for this is non blocking accept, this is something um you need to do if you have a lot of incomming connections, because the TCP handshake takes ages

But aside from that, if you use epoll consistently blocking calls are no problem

Here is an article describing when to use both in combination: https://eklitzke.org/blocking-io-nonblocking-io-and-epoll
But again this is something you only need for highly parallelizes high availability servers. I think for most people this is not so relevant
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 01:55:51 am
And if you continue talking stuff without any evidence behind it, I will start calling you what you are, a liar. At some point my good faith is over
I posted the numbers I get.  That's beyond evidence, it's _fact_.

As I said before, there is nothing special about my Windows installation with the possible exception that I keep it very clean.  Other than that, The ISO is from MS (the same one millions of other people have downloaded.) and there are very _few_ programs installed on it, VMware Workstation and TCCLE, which are the only two are use on a daily basis.

To recap, there is nothing special about my installation and you, and everyone else, should get results very close to those I posted.  If you don't get those results (outside of a VM) then you really should be looking at your Windows installation.

As far as testing Sleep, I've been testing its behavior for decades, I have long lost count of the number of machines in which I have tested it.

And attached is a screenshot for you.

Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 11, 2022, 02:01:37 am
Like how are you as someone who has never used LNet supposed to know any of that? Even if I ctrl click on the Identifier to look into CallAction, all I see is:
Code: Pascal  [Select][+][-]
  1. procedure TLUdp.CallAction;
  2. begin
  3.   if Assigned(FEventer) then
  4.     FEventer.CallAction;
  5. end;
Where FEventer.CallAction is an empty virtual method.
That's because you didn't look any further.
I also took a look and saw FEventer.CallAction pointed to an abstract method. But that's because TLUDP doesn't implement that abstract method but another one (not behind my computer now so I can't check the name). If you follow the correct one you end up in an event which uses fpSelect (like y.ivanov already mentioned). Synapse and Lazarus sockets etc work the same way (with the option of implementing several different method of FEventer.CallAction.

I didn't look very hard for documentation but shooting down code just by looking at the code and not understanding it, is wrong. In that case you can say the same thing about Lazarus and FPC on low level (with their multiple use of inc files which makes stepping through the source code that much harder than in Delphi). There is also very little documentation about the way it is fine there.

BTW The description in the docs for CallAction which explains the name.
Quote
ILComponent.CallAction - Method to eventize the component
This method is used to "eventize" the activity in given component.
It ensures that all network events are noticed and acted upon.

I also prefer another library (synapse) but that's more because I'm more familiar with that one and more bare boned (events and threads would need to be implemented but the user).

Quote
Indy is not perfect, but thats at least easy to understand and no ambigous "CallAction" or "Disconnect" or other things whose names make 0 sense in this context.
The need for calling CallAction is because TS insisted on implementing this in a program without TApplication. I'm sure if you wanted to do this with Indy components you would have the same problem and would need to call some kind of event-handler to make sure it could do its thing.

Edit:
And the more you dive into the source, the more you understand.
Quote
Also note that you need to only call CallAction on one of the protocols (or directly on the eventer) once per iteration (if you’re on non-visual lnet of course), otherwise you’re just calling the same thing multiple times (Protocol.CallAction calls Eventer.CallAction)
https://lnet.wordpress.com/usage/handles-eventers-and-events/
(That's why you ended up in an empty abstract event, which was the wrong place)

And if you use the components you don't need CallAction (same with Indy).
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 09:32:39 am
I posted the numbers I get.  That's beyond evidence, it's _fact_.
I don't doubt that you are getting these results, I doubt that this is the default behavior. Because from what you have written tell you only got these results consistently on one machine, and got similar results, but not consistently on a vm on this machine, and did not get these results on another (win10) vm on this machine.

I tested 3 VMs as well as native on 2 different machines, and I always got the exact same results everywhere. So it is quite clear that your behavior cannot be the normal windows behavior, as you only get the results consistently on one specific setup, while I get the other results consistently on all setups.

And this is why I call you a liar, calling your observed behavior the default behavior, when you know that the other behavior can be observed consistently accross many machines both virtual and physical, means that you are saying something that you know cannot be true, by definition a lie.
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 09:38:18 am
Quote
There is nothing wrong to work with non-blocking sockets as long as you do it properly. Most of the servers do it. Yes, that requires more deep knowledge, but what else doesn't requires it?
Usually non blocking socjets are used to serve many sockets on one thread to have more scalable server.
*snip*
Yes, I know. I also wrote an app or two.
Apart from the Berkeley sockets (incl. Winsock) I've used also other things, such as Win I/O completion ports, embedded libs like uIP, etc. And I prefer to use raw sockets just like you.

@prodingus
Does my suggestion solved your issue? BTW You should set the timeout for both sides, i.e. for the listener too, otherwise it will bump CPU to 100%
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 10:13:37 am
That's because you didn't look any further.
I also took a look and saw FEventer.CallAction pointed to an abstract method. But that's because TLUDP doesn't implement that abstract method but another one (not behind my computer now so I can't check the name). If you follow the correct one you end up in an event which uses fpSelect (like y.ivanov already mentioned). Synapse and Lazarus sockets etc work the same way (with the option of implementing several different method of FEventer.CallAction.
I'm not saying it's impossible to find out, but if you have to dive deep into the source code of a library, it's a bad library.

I didn't look very hard for documentation but shooting down code just by looking at the code and not understanding it, is wrong. In that case you can say the same thing about Lazarus and FPC on low level (with their multiple use of inc files which makes stepping through the source code that much harder than in Delphi). There is also very little documentation about the way it is fine there.
Yes I also find that the fpc and lazarus documentation are quite lacking, in fact I think this is the biggest problem with it. Every time you have to look into the source is annying and a failure of documentation, and every time it is more than ctrl click away (because of virtual methods), it basically doesn't exist for some users. The gold standard of course is if the code speaks for itself (which of course is not always possible), and if it doesn't, there should be enough documentation to resolve this.

BTW The description in the docs for CallAction which explains the name.
Quote
ILComponent.CallAction - Method to eventize the component
This method is used to "eventize" the activity in given component.
It ensures that all network events are noticed and acted upon.
Then why isn't it named "HandleNetworkEvents" or "ReactToNetworkEvents", or anyhting that conveys this message? Sure handling events involves calling some actions to handle those events, but this would be like saying "moving my eyes" instead of "reading". This reminds me of some very old projects of mine, where I was really lazy and called functions just "DoTheThing", it was good for a joke, and that I knew the code base in and out so this wouldn't be a problem, but when coming back after a few years, I had no idea what was happening in the code.
Naming is probably the most important part of Programming, especially for libraries, and I can't find anything positive about the name. It's not even short, it could easiely just be called "act" to have the same amount of useful information in the name but at least be short.

The need for calling CallAction is because TS insisted on implementing this in a program without TApplication. I'm sure if you wanted to do this with Indy components you would have the same problem and would need to call some kind of event-handler to make sure it could do its thing.
In the general flow Indy is not directly comparable (I just brought it up because of the naming and structure, not necessarily that it does the same thing in the same workflow), because in Indy handles non blocking sockets differently (basically it does not try to be smart as LNet but behaves exactly the sockets API would, i.e. the actual calls are non blocking, not that there is some magic CallAction function). If you use the event based Server component, it will execute the listening in a thread and then, if you want to handle the incomming events on the mainthread (default behavior) you must check the main threads eventQueue with CheckSynchronize. This is in workflow similar to CallAction, but there are two main differences, first the event handling is completely done with the general RTL functionality, that is likely to be known already, rather than introducing something specific to that library. But more importantly, it's not named CallAction (I can't stress enough how bad this name is).


Edit:
And the more you dive into the source, the more you understand.
And the more you dive into the source, the more you do something that should not be required to use a library. Having to consort the manual/documentation is bad, and usually a sign of bad structure, having to consult the source is worse. I shit a lot about Indy, but just by trial and error it is usally quite easy to find out how to do things. It is not perfect, for example to find out that the TUDPServer uses threads you also must look into the source, but at least the naming and structures make sense (e.g. UDP is not a connection).

The best libraries are those that can be discovered with nothing but autocomplete. Sure most libraries fall short of that benchmark, and I've written a few libraries myself that are too complicated to be self documenting, but then I usually try to either have extensively commented examples and some form of documentation (which in my case is usally a multi page readme, but TBH I am not so good with documentation myself). LNet has an UDP example, see what they write for CallAction:
Code: Pascal  [Select][+][-]
  1. FCon.CallAction;     // "eventize" the event loop in lNet
Great... words, but why not write anything someone can understand, e.g. "React to network events or wait up to Timeout if no events occured", you know the thing that is actually happening here.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 11, 2022, 10:37:59 am
@prodingus
Does my suggestion solved your issue? BTW You should set the timeout for both sides, i.e. for the listener too, otherwise it will bump CPU to 100%
I'm not TS but yes, it does work a lot better.
Putting in Sock.Timeout := 10000; makes it go down to 50% cpu in my VM (1CPU) without any sleep-lines.

(BTW, The reason it reaches 100% in a 1CPU VM is that there are multiple processes at work. project.exe is one of them (50%), conhost is another (30%) and Interrupts (15%). In a multi CPU machine, the processes are divided over the CPUs and the stress on the machine is a lot less.)

That's because you didn't look any further.
I also took a look and saw FEventer.CallAction pointed to an abstract method. But that's because TLUDP doesn't implement that abstract method but another one (not behind my computer now so I can't check the name). If you follow the correct one you end up in an event which uses fpSelect (like y.ivanov already mentioned). Synapse and Lazarus sockets etc work the same way (with the option of implementing several different method of FEventer.CallAction.
I'm not saying it's impossible to find out, but if you have to dive deep into the source code of a library, it's a bad library.
That's why Indy would be considered a "bad library" too, according to the same standards (although you are correct in that it does things differently).
Same goes for everything in Lazarus and FPC.

The only thing is that the maker of a library could name some things better or differently. But maybe English isn't their first language or they had some other reason in mind (which was the case here). But CallAction isn't normally called. If you work with the components in a Lazarus program, there is no need to call CallAction. It is done for you.

Quote
The CallAction method of all “Connections” is a method which “eventizes” the whole connection. It is valid only in non-visual lNet. Whenever you call this method, all sockets of given connection are checked for status updates (eg. if something can be received, if I can send…) and appropriate callbacks are fired. You need to call this method periodicly to assure functionality. You need to CallAction periodicly if you want to know if you can receive. (get)
https://lnet.wordpress.com/

Because lnet tries to be a small simple library and there aren't any threads, there must be something called to handle events. Creator decided it should be CallAction. I have no problems with that. There a lot of things in Indy that annoy me a LOT more.

(And like I already said, I like bare boned sockets or Synapse more, just because I need to do everything myself and have all in hand.)
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 10:38:45 am

*snip*
If you use the event based Server component, it will execute the listening in a thread and then, if you want to handle the incomming events on the mainthread (default behavior) you must check the main threads eventQueue with CheckSynchronize. This is in workflow similar to CallAction, but there are two main differences, first the event handling is completely done with the general RTL functionality, that is likely to be known already, rather than introducing something specific to that library.
*snip*
I've got an issue making this recently - using such a server component in Linux works pretty well, but when I tried to port that daemon in Windows as a TServiceApplication found that CheckSynchronize doesn't work as expected.
And to make it work I had to dig deep into the RTL sources and to read what was written in the forum, considering it may be obsolete, not relevant, etc. Having such an explicit method could save me a lot of time.
Just as a counterpoint. Not saying anything about the name.
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 10:39:20 am
I don't doubt that you are getting these results, I doubt that this is the default behavior. Because from what you have written tell you only got these results consistently on one machine, and got similar results, but not consistently on a vm on this machine, and did not get these results on another (win10) vm on this machine.

I tested 3 VMs as well as native on 2 different machines, and I always got the exact same results everywhere. So it is quite clear that your behavior cannot be the normal windows behavior, as you only get the results consistently on one specific setup, while I get the other results consistently on all setups.

And this is why I call you a liar, calling your observed behavior the default behavior, when you know that the other behavior can be observed consistently accross many machines both virtual and physical, means that you are saying something that you know cannot be true, by definition a lie.
You should measure your language a little more carefully.  It also seems  that you should learn a little about Windows and how an O/S scheduler works.

As far as VMs, as I hope you've been able to figure out, they _emulate_ hardware and no matter how good the emulation is, it's not perfect.  I don't expect VMs to operate exactly the same as real hardware but, apparently you do.

I'm not going to call you a liar but, the word that comes to mind starts with "i" and, that wouldn't be a lie, it would be an accurate description of your behavior.

That you don't seem to understand and that your non-VM machines are not working properly, is _your_ problem and, your problems don't make anyone a liar.

You got the screenshot you requested and, that is the picture of the reality you are unable to accept. 
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 10:52:27 am
@prodingus
Does my suggestion solved your issue? BTW You should set the timeout for both sides, i.e. for the listener too, otherwise it will bump CPU to 100%
I'm not TS but yes, it does work a lot better.
Putting in Sock.Timeout := 10000; makes it go down to 50% cpu in my VM (1CPU) without any sleep-lines.
As I expected.
It is not to use a big timeout (I don't think you should go over, e.g. 100 ms) but the main point is to give up the slice for the reason of I/O. Otherwise it is just a waste of time, a delay. 
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 11:30:25 am
As far as VMs, as I hope you've been able to figure out, they _emulate_ hardware and no matter how good the emulation is, it's not perfect.  I don't expect VMs to operate exactly the same as real hardware but, apparently you do.

[...]

That you don't seem to understand and that your non-VM machines are not working properly, is _your_ problem and, your problems don't make anyone a liar.
Please stop talking it is embarrassing how little you know about the subjects you talk about. Virtualization is not emulation: https://www.dell.com/en-us/blog/emulation-or-virtualization-what-s-the-difference/
A virtual machine runs on your actual hardware, the processes run on your real CPU and use your real memory, it does not emulate the hardware as you claim. The fact that you get this simple difference wrong shows that you have absolutely no idea about computing at all. I'm sorry but everything you said in this thread so far is factually and provably wrong. You try to lecture me and don't even know the very basics of computing. This is literal first semester CS knowledge, things you learn in the very first few month of getting any education in that area

The reason I call you a liar is not because you are wrong. You don't know much about virtualization and operating systems and this is fine, many people don't know this. But because you are claiming things that are wrong after being proven that they are wrong, and telling something that is not true while knowing it is not true is a lie.
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 11, 2022, 11:39:43 am
Please stop talking it is embarrassing how little you know about the subjects you talk about. Virtualization is not emulation: https://www.dell.com/en-us/blog/emulation-or-virtualization-what-s-the-difference/
A virtual machine runs on your actual hardware, the processes run on your real CPU and use your real memory, it does not emulate the hardware as you claim. The fact that you get this simple difference wrong shows that you have absolutely no idea about computing at all. I'm sorry but everything you said in this thread so far is factually and provably wrong. You try to lecture me and don't even know the very basics of computing.

That specific use of "virtual machine" is comparatively recent. From the time that IBM introduced VM up until some of the later 68Ks etc., it was common to refer to "virtualised hardware", and on the '386 there was "Virtual 8086 mode". At the same time, "virtual machine" was still synonymous with "interpreter", possibly augmented with JIT translation, as used by the P-System, the PARC implementation of Smalltalk and so on.

It's only recently that people who are convinced that computing begins and ends with PC have redefined "Virtual Machine" to be the same as "virtualised hardware", and even there there are grey areas depending on precisely what happens when e.g. direct access of a network device is attampted.

So please, both of you: cool it. And there's no need for anybody to use the L-word.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 11:51:42 am
That's why Indy would be considered a "bad library" too, according to the same standards (although you are correct in that it does things differently).
Same goes for everything in Lazarus and FPC.
Yes and no. Indy get's away with a lot more because it is much better structured. With Indy I usually got most things I wanted by must creating a component, and then pressing ctrl+space to get code completion and just look at the names of the functions and properties. For example to create an UDP server, I never created a UDP server with indy, it took me like 10 minutes to learn this from scratch by just looking at the code completion, no need to look in the documentation nor the source.
So yes the documentation is lacking, but at least I get around without spending hours on googling or reading the source.

And again, I agree that the documentation in Lazarus and FPC is very lacking, and there are a lot of things that I think are bad because of that. I often search for "delphi xxx" rather than "lazarus xxx" because I know the delphi documentation is going to be better. Just compare the Documentation of Synchronize in Delphi:
Quote
Description

Executes a method call within the main thread.

Synchronize causes the call specified by AMethod to be executed using the main thread, thereby avoiding multithread conflicts. The AThread parameter associates the caller thread.

For static methods, you can associate AMethod with any thread using the AThread parameter. Also, you can use nil/NULL as AThread parameter if you do not need to know the information for the caller thread in the main thread.

In the current implementation, the Synchronize method can use associated thread information to wake-up the main thread on Windows platforms.

If you are unsure whether a method call is thread-safe, call it from within the Synchronize method to ensure that it executes in the main thread.

Execution of the current thread is suspended while the method executes in the main thread.
Warning: Do not call Synchronize from within the main thread. This can cause an infinite loop.
Note: You can also protect unsafe methods using critical sections or the multiread exclusive-write synchronizer.

An example of when you would want to use Synchronize is when you want to interact with either a VCL or a FireMonkey component. Use an in-place anonymous method to solve the problem of passing variables to the method you want to sychronize:
And here is the same description for FPC:
Quote
(yes there is no description, the documentation is literally just the function signature)

This is really bad, and I think the biggest problem with FPC/Lazarus.

Again the problem with LNet is not the missing documentation, nor the naming, it's all of the small issues combined that makes it exceptionally bad. Especially the general structure in combination with the naming and lack of documentation. It's not just CallAction, as mentioned earlier, why is a UDP socket a connection and has methods like disconnect? If I see something like that in a code, I would either assume that this socket is a conncetion based socket, like TCP, or if I know it's UDP, I would consider this to be a mistake.
It's just bad from front to back. I haven't seen anything good about this library so far, except maybe that it works
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 11:58:46 am
That specific use of "virtual machine" is comparatively recent. From the time that IBM introduced VM up until some of the later 68Ks etc., it was common to refer to "virtualised hardware", and on the '386 there was "Virtual 8086 mode". At the same time, "virtual machine" was still synonymous with "interpreter", possibly augmented with JIT translation, as used by the P-System, the PARC implementation of Smalltalk and so on.

It's only recently that people who are convinced that computing begins and ends with PC have redefined "Virtual Machine" to be the same as "virtualised hardware", and even there there are grey areas depending on precisely what happens when e.g. direct access of a network device is attampted.
"recently" in this context means just 30-40 years old. From the 70 years of computing history, it's about half of that period. The current understanding of VM is closer to the introduction of the Personal Computer than it is to today.

Arguing something like this is a very cheap opt out, and I don't let something like this count. I don't want to be lectured by someone about how modern computers work who 1. either doesn't know anything about computers, or  2. whose knowledge of computers is stuck 30 years ago.
Maybe you are right and I shouldn't call him a liar, but at the very least he ist trying to lecture me on things he clearly has no idea about
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 11, 2022, 11:59:17 am
... why is a UDP socket a connection and has methods like disconnect?
I was under the impression Indy also has Connect and Disconnect for TIdUDPClient  :D

Yep.
Code: Pascal  [Select][+][-]
  1.   TIdUDPClient = class(TIdUDPBase)
  2. //...
  3.   protected
  4.     procedure DoOnConnected; virtual;
  5.     procedure DoOnDisconnected; virtual;
  6.   public
  7.     procedure Connect; virtual;
  8.     procedure Disconnect; virtual;
  9.     function Connected: Boolean;
  10. //...
  11.   end;

But Indy is a much more structured and comprehensive library. It works with threads etc.

But it isn't written in 1000 lines of code (which lnet is, well, it was, it's a bit larger now :) ).
Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 11, 2022, 12:14:27 pm
Arguing something like this is a very cheap opt out, and I don't let something like this count. I don't want to be lectured by someone about how modern computers work who 1. either doesn't know anything about computers, or  2. whose knowledge of computers is stuck 30 years ago.
Maybe you are right and I shouldn't call him a liar, but at the very least he ist trying to lecture me on things he clearly has no idea about

I for one would prefer that you didn't use insults like that in open discussion. It's not necessary, it lowers the tone of the forum, and it definitely doesn't help resolve any of OP's issues.

As far as VMs are concerned: people still refer to the Java VM, the .Net VM and so on, and in fact the entire field of virtualisation, simulation and emulation is generally poorly-delimited. Whole-system virtualisation is one particular subset of that field, and punding your shoe on the desk and demanding that your definition is the only acceptable one doesn't help anybody.

And while I have absolutely no intention of investing my limited time in this, I'd add that whenever I've seen anybody demonstrate absolutely consistent results from a non-realtime scheduler it's turned out that his methodology is flawed. Although sometimes it's taken a 'scope to track down what was really going on.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 12:16:50 pm
Maybe you are right and I shouldn't call him a liar,
You had an epiphany, it might be worth marking the date on the calendar.

trying to lecture me on things he clearly has no idea about
Trying to educate you obviously failed and, lecturing you apparently did too. 

Title: Re: cannot receive messages; udp server with lnet
Post by: MarkMLl on July 11, 2022, 12:21:20 pm
Maybe you are right and I shouldn't call him a liar,
You had an epiphany, it might be worth marking the date on the calendar.

trying to lecture me on things he clearly has no idea about
Trying to educate you obviously failed and, lecturing you apparently did too.

(Clears throat) Please don't make things worse. I think this subthread could usefully wind down.

MarkMLl
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 12:36:06 pm
Trying to educate you obviously failed and, lecturing you apparently did too.
Sorry, I don't need education from someone who clearly doesn't know what a VM is. You know the truely sad thing is, before writing a post, I usually try to double check if what I am writing is correct, I get my old university scripts, some books I have around, google for documentation or other information and always try the things out in code. Meanwhile you blast out things like a VM is an emulator, which is wrong after just two seconds of googling.

I have a question, you where wrong with all of your statements in this thread, but let's focus on the last one about vms and emulation, because there is no way you can argue against that you where completely wrong ther. Doesn't it bug you that you are so easiely wrong on such things? Why can't you accept that someone else might know more about a topic than you?
You claimed it like it is some form of gotcha moment, to just say that I don't know what a VM is, yet you where completely and utterly wrong about that. Doesn't that make you feel you should maybe look up stuff before claiming it? Something like the claim that a vm is an emulator should have never happend if you had at least some rigorous approach to verifying your claims before making them. Yet you are wrong so many times and refuse to learn.
I'm just curious if you don't have any drive to at least try to be right, at least once, or why are you always blasting falshoods with the confident like you where the omniscient tech god who knows everything
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 12:51:31 pm
(Clears throat) Please don't make things worse. I think this subthread could usefully wind down.

MarkMLl
You're right about that.  I'm not making things better but, he really asked for it and, continues asking for it.



Sorry, I don't need education from someone who clearly doesn't know what a VM is.
Neither you nor anyone else for that matter.

You know the truely sad thing is, before writing a post, I usually try to double check if what I am writing is correct,
In that case, I suggest you start triple checking because double checking isn't doing the trick.

Meanwhile you blast out things like a VM is an emulator, which is wrong after just two seconds of googling.

I have a question, you where wrong with all of your statements in this thread, but let's focus on the last one about vms and emulation, because there is no way you can argue against that you where completely wrong ther. Doesn't it bug you that you are so easiely wrong on such things? Why can't you accept that someone else might know more about a topic than you?
There is a little problem with that belief of yours.  The problem is this: have you tried running a VM inside a VM ?... just in case you haven't, current VM software can't do it.  Any ideas why by any chance ?  Can you explain why most VM software can't do that ?

Something like the claim that a vm is an emulator should have never happend if you had at least some rigorous approach to verifying your claims before making them.
A VM emulates a machine, some of that emulation is done with hardware assistance from the CPU and some of it is done in software.

I'm just curious if you don't have any drive to at least try to be right, at least once
I've been right more than once and the screen shot I posted, which you requested, proves it.  Look it up again if you need to.

Title: Re: cannot receive messages; udp server with lnet
Post by: marcov on July 11, 2022, 12:58:47 pm
IIRC lnet's author mainly wanted to use epoll/kqueue or select as last resort.

I objected that lnet also should work on lnet (I was and still am an Indy user), so he also dove into Windows.

Ales was quite clever, but the result, like Synapse, is a bit too Unix centric for my tastes and Indy is simply more complete and well supported by Remy. (nowadays even on this forum)

As it happens in the last few years I picked up indy again (both udp and tcp clients and servers for internal communication of machine parts and to the outside world, so no protocol usage), and put all of them in an own  thread to minimally disturb other threads, and also avoid polling as much as possible. I'm quite happy how it all turned out, and it turns this can be done without modifying Indy. (but the result I think is Windows specific)
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 01:05:12 pm
There is a little problem with that belief of yours.  The problem is this: have you tried running a VM inside a VM ?... just in case you haven't, current VM software can't do it.  Any ideas why by any chance ?  Can you explain why most VM software can't do that ?
You must be kidding right? This is possible, vmwares ESXi virtualizer can do this for ages, virtualbox is also easiely capable of doing that and even Microsofts HyperV is capable of doing that since 2016: https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/user-guide/nested-virtualization
Please at least use google before trying to set up a gotcha question. This is just embarrasing how confident you are in being wrong.

Also if these VMs would actually emulate the hardware this would be no problem, for example I can run an ARM emulator within an x86_64 VM, and can easiely run a Playstation emulator within that emulator.

A VM emulates a machine, some of that emulation is done with hardware assistance from the CPU and some of it is done in software.
No it executes code on the real hardware in an emulated environment. And as the program measuring sleep time does not interface with the environment (i.e. network, external devices, etc.) it doesn't matter that they are emulated. It is the real NT kernel running on a real CPU using real memory.

I've been right more than once and the screen shot I posted, which you requested, proves it.  Look it up again if you need to.
Well said in a post where you where again completely and utterly wrong, and could have found that out with just 1 second of googling
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 01:55:00 pm
No it executes code on the real hardware in an emulated environment.
And what environment is it that it is emulating ?... it isn't emulating Windows because that has to be installed.

The saying goes, you should quit while you're ahead but, in your case, you should quit before you get further behind.

It would be good too because this thread isn't about your religious beliefs about the scheduler and/or VMs.  That would be convenient, no more litter.

Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 02:05:51 pm
And what environment is it that it is emulating ?... it isn't emulating Windows because that has to be installed.
Peripheral hardware such as network adapter, disk, display, etc. You know all the stuff that isn't part of a core computer. Why would I be talking about windows? You must truely know nothing about computers if you would consider this being a vritual environmnet.

It would be good too because this thread isn't about your religious beliefs about the scheduler and/or VMs.  That would be convenient, no more litter.
All I'm doing is pointing out how wrong you are. I don't care that you know so little about computing, but the worst thing that could happen is that someone would read your posts and assume you are anything but a fool who doesn't know anything you are talking about, so every time you write something stupid, like that you cant create a vm inside a vm, which is factually wrong, I need to point out how wrong you are.

Note that every time you say something stupid, I don't "religously" just say you are wrong, I always provide counter examples or links with information how wrong you are. You are the one who never put anything forward

Also it's funny that you are completely wrong with your gotcha questions so you just silently drop these points. Why can't you just accept that you were wrong, like you were with everything else in this thread?
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 02:11:54 pm
Also it's funny that you are completely wrong with your gotcha questions so you just silently drop these points. Why can't you just accept that you were wrong, like you were with everything else in this thread?
Of course... and the Democrats should admit Biden stole the U.S election and Ukraine attacked Russia.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 02:14:13 pm
So you say you weren't wrong with nested VMs? I'm curious how you deny reality for this case.
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 02:31:45 pm
So you say you weren't wrong with nested VMs? I'm curious how you deny reality for this case.
Well... a little googling brought this up:
Quote
Nested virtualization is not automatically offered as a feature and this is also true for various third party virtualizers. For example while the VirtualBox virtualizer has existed for years, the ability to run VirtualBox inside VirtualBox using Intel CPUs was only offered as a feature in v6.1 released in 2020. [2] This demonstrates that extra code is required for this functionality and that also implies a greater attack surface.
Apparently, you are right on that one, as of 2020 (kind of recent) it is possible to run a VM in another VM (quite likely because CPU manufacturers have been adding circuitry in order to enable that.) I seriously doubt that ability is available on CPUs 5 years or older.

You got one right... good for you but, that doesn't mean the VM isn't emulating functionality in software. Far from it.
Title: Re: cannot receive messages; udp server with lnet
Post by: marcov on July 11, 2022, 02:43:16 pm
Afaik VMWare already could do this already longer, but the nested VM would not be accelerated. There are several virtualization related extensions, and through the years more and more have become nestable.

Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 02:46:37 pm
Afaik VMWare already could do this already longer, but the nested VM would not be accelerated. There are several virtualization related extensions, and through the years more and more have become nestable.
My copy of VMware is from 2015 and it does not allow nesting but, it may also be because I'm running an i860.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 03:11:29 pm
Apparently, you are right on that one, as of 2020 (kind of recent) it is possible to run a VM in another VM (quite likely because CPU manufacturers have been adding circuitry in order to enable that.) I seriously doubt that ability is available on CPUs 5 years or older.
As I have written, Windows supported this feature in HyperV since 2016, so for 6 years, which is more than 5 years. So you are wrong... again

Also again this point is actually kindof moot anyway, because it actually supports the argument that this is because virtualization is not emulation. In my Emulated QEMU ARM Linux session I can easiely start another emulator, because emulation completely abstracts from the underlying hardware, while virtualization requires hardware and host virtualizer software support to share the hardware with between the different devices, because it is exactly *not emulation*

You got one right... good for you but, that doesn't mean the VM isn't emulating functionality in software. Far from it.
So you say that because some things are emulated, this means a VM is an emulator. Guess what, on you normal windows system you also have emulated environments. E.g. virtual network interfaces, like the ones created by your VM host software. Or guess what a virtual filesystem like a network drive is: According to your same logic this means that also a native windows installation is just an emulator.

The Core of a VM is exactly to not do emulation but virtualization of hardware. It provides additonally emulated behavior for peripherals, but this is an add-on and is not required for a vm

Please stop shifting the discussion. You stated
Quote
As far as VMs, as I hope you've been able to figure out, they _emulate_ hardware and no matter how good the emulation is, it's not perfect.  I don't expect VMs to operate exactly the same as real hardware but, apparently you do.
In the context of a program that is only running on the CPU, and does not interact with any peripheral hardware. And this is not emulated, simple as that. Therefore you are just dead wrong here.

Also you don't need any emulation with a VM. If you have a dedicated graphics card and networkcard for the VM, you can fully use a VM without any emulated peripherals, just by using bare metal hardware access through PCI pass-through provided by the virtualizer.

I actually did something like this once, where I wanted to run my windows partition without having to reboot from linux, so I mounted it into a vm, passed my graphics card through it, let linux only run on the integrated graphics card, an basically had a fully fledged windows on one monitor and a linux on the other one, running on the same machine, both running on fully native hardware

My copy of VMware is from 2015 and it does not allow nesting but, it may also be because I'm running an i860.
I think you need EXSi virtual machines, I don't know if it supports HyperV nesting
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 03:36:23 pm
As I have written, Windows supported this feature in HyperV since 2016, so for 6 years, which is more than 5 years. So you are wrong... again
For someone who pretends to know so much, you sure make statements that are rather flimsy.  It's _not_ just a matter of the O/S, Windows or other, it's much more a matter of having virtualization supported in hardware, that is by the CPU itself.

Try to virtualize a machine on an 8086 running MS-DOS ... good luck.

Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 03:49:34 pm
For someone who pretends to know so much, you sure make statements that are rather flimsy.  It's _not_ just a matter of the O/S, Windows or other, it's much more a matter of having virtualization supported in hardware, that is by the CPU itself.
Have you read the link that I posted above? There are no hardware requirements. Any Intel CPU that is VT-x capable can do it. So you could even use older Intel CPUs, even the Intel Atom form 14 years ago. Thats more than 5.
Isn't it amazing how much you can learn if you would just read the information given to you.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 11, 2022, 03:52:25 pm
@y.ivanov

Timeout did the trick! Now the cpu is @ ~15-20%.

Quote
the Sock.CallAction will call fpSelect() and as long there is a Sock.Timeout > 0 it will behave as expected.
Default is Sock.Timeout = 0 and because of that the CPU utilization will be 100% unless a sleep(x) added (but then everything will slow down).
Correct.

Quote
Does my suggestion solved your issue? BTW You should set the timeout for both sides, i.e. for the listener too, otherwise it will bump CPU to 100%

yes, but as posted here too, https://forum.lazarus.freepascal.org/index.php/topic,13053.0.html (https://forum.lazarus.freepascal.org/index.php/topic,13053.0.html), every other value >1 sould add more delay,but it doesn't! It's like I getting alwasys the minimum delay.

Quote
Yes I also find that the fpc and lazarus documentation are quite lacking, in fact I think this is the biggest problem with it. Every time you have to look into the source is annying and a failure of documentation, and every time it is more than ctrl click away (because of virtual methods), it basically doesn't exist for some users. The gold standard of course is if the code speaks for itself (which of course is not always possible), and if it doesn't, there should be enough documentation to resolve this.
AMEN to that too!

more replies later, TMI !!!
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 03:56:52 pm
There are no hardware requirements. Any Intel CPU that is VT-x capable can do it.
No hardware requirements, except VT-x.  nice!
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 04:05:11 pm
Ah sorry I forgott how ignorant you are. Of course I meant "No *additional* hardware requirements". I assumed that it would be pretty clear that nested Hyper-V would inherit the hardware requirements from Hyper-V, but because I am so nice, for someone like you who doesn't understand this, I of course spell it out directly, you need at least a Hyper-V capable intel-CPU (i.e. one with VT-x support) to use Hyper-V.

Again sorry for that, I sometimes forgett that you don't have the brain capacity to make such simple inferrences

Or do you just pretend to be stupid so I miss that you completely dropped the point after I again showed you how wrong you are, with information that you already had, you didn't even need to google for that?
Nice try, thats now another point you where provably wrong about in this thread

I must say this is actually quite fun, it's like arguing with a child, you clearly have no idea what you are talking about, and disproving you literally just takes 2 seconds of reading the stuff. But you are to stubborn to admit that you are out of your debt so you keep bringing up new points that can be proven false within a few seconds of looking it up. And every time you bring something new up, I can show it to be wrong and you are just making a fool out of yourself
Title: Re: cannot receive messages; udp server with lnet
Post by: SymbolicFrank on July 11, 2022, 04:10:03 pm
About timing: the original IBM PC had a real-time clock, that generated a timer tick interrupt 18.2 times a second, which was available through the BIOS. Yes, an IMB PC also had a second timer, but it was needed for I/O timing. And the AT had yet another one, but that needed to share an interrupt. If you wanted to time stuff, for example for making sound, you could write a new frequency to the speaker chip 18.2 times a second. That was it. Or, continuously, of course. So, for multitasking, the idea was that you would do a bit and yield to the next process with sleep(0). And with Windows, up to 95, 18.2 times a second the scheduler took control and suspended the task if it didn't and there were more.

That first PC ran at 4.77 Mhz and could execute less than 1 million instructions on average each second. Context switching took a fairly long time (~180 instruction cycles) and software floating point calculations were slow. So, if just handling an interrupt or waiting for something, a few thousand cycles is plenty. But reading from memory, performing some floating point ops and writing it back was a fairly lengthy task. And the OS had to handle interruptions for I/O, or doing calculations in between each scan line. So, with, say, 1000 context switches a second, there was little time left for the processes to actually do something useful.

And it isn't all that easy to make a good timing source anyway. Like, the IBM PC had a dedicated 16-bit timer as well, which was used for I/O timings and such. And with a single CPU, everything was handled through interrupts. So, it wasn't going to be very accurate anyway. Like: write a byte to the UART, read a few bytes from the disk drive, move the disk head to the next track, read a byte from the other UART, oh, and run a bit of the user's program in between.

Although the IBM AT also had a high resolution real-time timer tick (1024 ticks a second).

At some point (one of the Pentiums, IIRC) Intel started to add other timings to the CPU. At first it was just the amount of CPU cycles, but that has been extended quite a bit (https://www.intel.com/content/www/us/en/develop/documentation/vtune-help/top/reference/cpu-metrics-reference.html) That cycle counter was the first high-speed performance counter. Still not very accurate, but with a high resolution.

So, all in all, it took quite a while before good timing was generally available, and all through new API's. The basics are still the same. And therefore Microsoft still expects that sleep(1) results in a delay of ~55 milliseconds.

Ok, the resolution is a bit higher, it depends on when in your allotted time slice you execute that call and how many other processes are waiting to be scheduled. And half the reason why that has never been changed is, because many software used that to do their internal timing. It was a choice between that and a spinlock that uses 100% CPU time.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 11, 2022, 04:16:58 pm
Quote
I for one would prefer that you didn't use insults like that in open discussion. It's not necessary, it lowers the tone of the forum, and it definitely doesn't help resolve any of OP's issues.

I would also like just a liitle bit more lower tone, but agreed-to-disagree disagreements are usefull for pointing things out. ;)

As far for the network thing, I will try to use something else, like Warfley's wrapper or raw sockets, but my time is limited. There are many things to learn, I was't expecting networking to be so demanding, and to my surprise sleep/delay seems to be only good for delaying, well, I don't know, just message outputs (?), but surelly not main execution loop.
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 04:22:17 pm
@y.ivanov

Timeout did the trick! Now the cpu is @ ~15-20%.

Quote
the Sock.CallAction will call fpSelect() and as long there is a Sock.Timeout > 0 it will behave as expected.
Default is Sock.Timeout = 0 and because of that the CPU utilization will be 100% unless a sleep(x) added (but then everything will slow down).
Correct.

Quote
Does my suggestion solved your issue? BTW You should set the timeout for both sides, i.e. for the listener too, otherwise it will bump CPU to 100%

yes, but as posted here too, https://forum.lazarus.freepascal.org/index.php/topic,13053.0.html (https://forum.lazarus.freepascal.org/index.php/topic,13053.0.html), every other value >1 sould add more delay,but it doesn't! It's like I getting alwasys the minimum delay.
*snip*
It doesn't work that way. It is a timeout. After that time the OS (fpSelect) will just give up waiting and the control will be transferred back to the calling (your) process again. That is, the CallAction will return with no data processed. In the case data appears earlier - the control will be transferred back without further waiting.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 11, 2022, 04:26:31 pm
I would also like just a liitle bit more lower tone, but agreed-to-disagree disagreements are usefull for pointing things out. ;)
Agree to disagree gives undue credit to another oppinion that it is something that is disagreeable. So far 440bx made one factually incorrect statement after another. This is no point of contention, this is something that needs to be pointed out. And when he tries to lecture me, even though he is grossly incorrect (and I have given counter examples or links with additional information to every single claim he made) than I am going to ridicule him for that. Again if anyone reads this, they shouldn't get away thinking "oh this is a contentious issue", because it isn't. One is right, the other one is making a fool out of themselves bringing up point after point which is just completely and factually wrong.

Also it's way to much fun, disproving the stuff that 440bx posts here is just way too easy.

The only thing I give him is that the results he gets for the sleep duration on his machine are indeed interesting, and if he wasn't so stubborn, and demanding that this is the only correct behavior and all my other machines are just broken if I don't get the same results, maybe one could find out why this is the case and why it behaves so differently than on other machines.
Personally I think the attitude "my oppinion is correct and everything that doesn't conform to it must be wrong" is just nothing that brings anyone forward
Title: Re: cannot receive messages; udp server with lnet
Post by: alpine on July 11, 2022, 04:32:30 pm
Quote
I for one would prefer that you didn't use insults like that in open discussion. It's not necessary, it lowers the tone of the forum, and it definitely doesn't help resolve any of OP's issues.

I would also like just a liitle bit more lower tone, but agreed-to-disagree disagreements are usefull for pointing things out. ;)

As far for the network thing, I will try to use something else, like Warfley's wrapper or raw sockets, but my time is limited. There are many things to learn, I was't expecting networking to be so demanding, and to my surprise sleep/delay seems to be only good for delaying, well, I don't know, just message outputs (?), but surelly not main execution loop.
The communications are not so simple as one might expect and that is because they inherently involve multiprocessing issues, there is at least two participants and that is in fact multiprocessing. Even when it seems like from one side it isn't.
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 11, 2022, 04:33:34 pm
Quote
The only thing I give him is that the results he gets for the sleep duration on his machine are indeed interesting, and if he wasn't so stubborn, and demanding that this is the only correct behavior and all my other machines are just broken if I don't get the same results, maybe one could find out why this is the case and why it behaves so differently than on other machines.
Personally I think the attitude "my oppinion is correct and everything that doesn't conform to it must be wrong" is just nothing that brings anyone forward
You couldn't have said it better!!  ;D
Title: Re: cannot receive messages; udp server with lnet
Post by: prodingus on July 11, 2022, 04:36:21 pm
Quote
It doesn't work that way. It is a timeout. After that time the OS (fpSelect) will just give up waiting and the control will be transferred back to the calling (your) process again. That is, the CallAction will return with no data processed. In the case data appears earlier - the control will be transferred back without further waiting.
Then why the amount to be specified in the timout()?
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 11, 2022, 04:42:28 pm
Quote
It doesn't work that way. It is a timeout. After that time the OS (fpSelect) will just give up waiting and the control will be transferred back to the calling (your) process again. That is, the CallAction will return with no data processed. In the case data appears earlier - the control will be transferred back without further waiting.
Then why the amount to be specified in the timout()?
Because normally you would have more in your program flow than only the reading of communication. Screen handling, countdown label, other buttons and other tasks (sending messages for example), etc. etc.

You set the timeout to some value to which you expect a package to arrive.
If it hasn't arrived by than you will want to return to your program so it can do other stuff.

If you set your timeout to 20 seconds, the program will wait until you receive something or 20 seconds have passed.
But 20 seconds might be too long for your user to wait. So you will lower it.

But setting it too low isn't helpful either because for example if you set it at 10ms and you expect normal reaction at 100ms, then every time returning to your own program flow will also take extra time (you don't need to update the screen every 10ms). If that's not needed a timeout of 100ms might seem more appropriate.

So it all depends on your program design (which you need to think about before doing any programming  ;) )
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 04:46:53 pm
Ah sorry I forgott how ignorant you are. Of course I meant "No *additional* hardware requirements".
but, of course...

You're getting really pathetic.  It would be a good idea for you to step away from the keyboard. 
Title: Re: cannot receive messages; udp server with lnet
Post by: marcov on July 11, 2022, 04:50:15 pm
You're getting really pathetic. 

ENOUGH, both of you.
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 11, 2022, 05:36:30 pm
ENOUGH, both of you.
I agree with you... more than enough.


Title: Re: cannot receive messages; udp server with lnet
Post by: paweld on July 12, 2022, 04:28:29 pm
I was very curious about the differences you get when calling sleep and did tests on several systems I have access to:
- notebook with Windows 10
- 2x servers with Windows Server OS
- vm on HyperV with Windows Server OS
- vm on VirtualBox with Windows XP
- vm on VirtualBox with Windows 10

On all configurations for sleep(X) where X is less than about 100ms the results are as @Warfley wrote.

But (!!) if I run on computer at least one VM (checked on a Windows 10 notebook) - the results are as @440bx wrote.
After shutting down the VMs the results back to the values given by @Warfley.
Results on attachements.

Have a nice day.
Title: Re: cannot receive messages; udp server with lnet
Post by: SymbolicFrank on July 13, 2022, 11:27:20 am
What Microsoft says about it (https://docs.microsoft.com/en-us/windows/win32/procthread/scheduling).

Not all schedulers are created equal. In the past, we had Bulldozer CPU's, where two logical cores shared one unit for complex opcodes, like division, multiplication and complex addressing. So, it makes the most sense to first fill only the even or uneven cores and only use the other half of the pairs when they get swamped. And with the P-cores and E-cores of the current Intel's CPU's, it makes sense to use the P-cores for applications and the E-cores for lightweight threads, like drivers and stuff.

And, of course, if possible, it is best to schedule tasks on the same core every time (L1 cache). With AMD, the same chiplet (L2 cache). If that isn't practical, the same CPU (L2-3 cache). Failing that, the same system / processor group (memory). Context switches take a variable amount of time that way. Also, memory access. Access of a mapped page is fast. Mapping a table takes time. Loading it from disk is even slower. Reloading part of the page table from disk is slowest. You need to load the process somewhere. And garbage collectors can periodically use quite some processing time. Especially in a VM / docker container there's a lot of layers for all that stuff.

Internally, the scheduler keeps a list with all processes and a queue with running processes, their priorities and affinities. Blocked threads that are waiting for I/O have a high priority, but are best scheduled on an E-core. Etc. And this queue is updated periodically.

So, if you are going to look at all the individual timings, they can vary wildly. And if you graph them all, you might be able to determine what happened in the background and in the scheduler.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 13, 2022, 06:25:53 pm
But (!!) if I run on computer at least one VM (checked on a Windows 10 notebook) - the results are as @440bx wrote.
After shutting down the VMs the results back to the values given by @Warfley.
Results on attachements.

Have a nice day.
This is actually really interesting, I can't reproduce this locally with my VMs (I'm using VMWare Player without Hyper-V), if you are using microsofts Hyper-V it could be that Windows is using a different scheduling strategy when hyper-v is used, while when I am using VMWare with the vSphere hypervisor, windows doesn't know about that (directly) and proceeds as usual. If I have some time I will try it with Hyper-V (I usually don't use Hyper-V because I am using some VM softwares that do not support it, and they don't work if Hyper-V is enabled) but as it requires multiple reboots to turn on and off, I can't do it right away
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 14, 2022, 12:34:55 am
@Warfley and @440bx
I have a question.
I haven't entirely followed the subdiscussion here (due to some of the language) but I gather that Warfley has results ranging in 15, 15 and 30 seconds for 1000x 1, 8 and 16 ms sleep, and 440bx has much faster results even with 1 and 8 ms tests. Is that correct?

I get the same 15, 15 and 30 seconds result. In both FPC and Delphi

I found a simular problem with .NET sleep.
https://stackoverflow.com/questions/23215970/system-threading-timer-vs-system-threading-thread-sleep-resolution-net-timer

Although the default current time resolution is 1.000 ms for me in Windows 10 Pro 64 bit...
Is it possible, somehow, that the timer resolution which sleep uses, is switched to 15ms (so every sleep is minimum of 15ms).

(At least the System.Threading.Timer seems to be limited to a minimum of 15ms sleep)

Quote
C:\Users\Rik>Clockres.exe

Clockres v2.1 - Clock resolution display utility
Copyright (C) 2016 Mark Russinovich
Sysinternals

Maximum timer interval: 15.625 ms
Minimum timer interval: 0.500 ms
Current timer interval: 1.000 ms

(Please tell me if I don't know what I'm talking about because I'm only investigating this for the last 10 minutes  :D )

O, wow. Yes. I might be on to something.
@Warfley, could you add the NtSetTimerResolution to your example.

Code: Pascal  [Select][+][-]
  1. type NTSTATUS = ULONG;
  2. function  NtSetTimerResolution(RequestedResolution : ULONG; Set_ : BOOLEAN; ActualResolution : PULONG ): NTSTATUS; stdcall; external 'ntdll';
  3. var actualResolution: ULONG;
  4. //...
  5.   NtSetTimerResolution(1, true, @actualResolution);
  6.   writeln('was or is ?? ', actualResolution);

With these lines I get these results:
(MUCH better then the 15, 15 and 30 seconds you were getting)
Quote
ms : 1 repeat count 1000
Total time: 1.465s

ms : 8 repeat count 1000
Total time: 8.356s

ms : 16 repeat count 1000
Total time: 16.315s
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 14, 2022, 06:31:00 am
I gather that Warfley has results ranging in 15, 15 and 30 seconds for 1000x 1, 8 and 16 ms sleep, and 440bx has much faster results even with 1 and 8 ms tests. Is that correct?
That sounds right.

Is it possible, somehow, that the timer resolution which sleep uses, is switched to 15ms (so every sleep is minimum of 15ms).
As you have found out, the timer resolution can be changed but, I don't know under what circumstances Windows decides to change it.

Quote
C:\Users\Rik>Clockres.exe
(MUCH better then the 15, 15 and 30 seconds you were getting)
Quote
ms : 1 repeat count 1000
Total time: 1.465s

ms : 8 repeat count 1000
Total time: 8.356s

ms : 16 repeat count 1000
Total time: 16.315s
Those results look as they should be.  That said, it looks like there are common situations where Windows uses a different resolution resulting in values that vary significantly from those.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 14, 2022, 10:57:29 am
When using a VM with HyperV I also get the smaller tick counts:
Code: Text  [Select][+][-]
  1. ms : 1 repeat count 1000
  2. Total time: 1.949s
  3.  
  4. ms : 8 repeat count 1000
  5. Total time: 8.788s
  6.  
  7. ms : 16 repeat count 1000
  8. Total time: 16.600s
So windows changes the resolution for hyper-v. I would guess that it is also dependent on the CPU model, I tested on my Threadripper and my i7 laptop, so two very common CPU models (well threadripper not really but the underlying archtiecture is a Ryzen 1st gen, which is rather common), so I get the "common" result of 16ms.
Maybe 440bx has some "exotic" cpu. This would also explain VMs get the same result (both on his side as on mine), as VMs are running on the same CPU, it would be expected that the OS would choose the same timer interval there.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 14, 2022, 10:59:37 am
So windows changes the resolution for hyper-v. I would guess that it is also dependent on the CPU model, I tested on my Threadripper and my i7 laptop, so two very common CPU models (well threadripper not really but the underlying archtiecture is a Ryzen 1st gen, which is rather common), so I get the "common" result of 16ms.
Maybe 440bx has some "exotic" cpu. This would also explain VMs get the same result (both on his side as on mine), as VMs are running on the same CPU, it would be expected that the OS would choose the same timer interval there.
Did you try my NtSetTimerResolution suggestion at the place where you got the long delays (outside of a VM)?

PS. In my Hyper-v Windows 10 I also got 16, 16 and 31 seconds.
Using NtSetTimerResolution there it also went down to 1.6, 8.6 and 16.2

Maybe 440bx has some permanent setting in his Windows for this resolution.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 14, 2022, 11:07:34 am
O, and I see it also matters which version of Windows 10 you are using.
See this article:
https://randomascii.wordpress.com/2020/10/04/windows-timer-resolution-the-great-rule-change/

Putting in this in the example also works to make it faster.

Code: Pascal  [Select][+][-]
  1.  TimeBeginPeriod(1);

Quote
ms : 1 repeat count 1000
Total time: 1.890s

ms : 8 repeat count 1000
Total time: 8.581s

ms : 16 repeat count 1000
Total time: 16.752s

Now to find the permanent setting for this  :P

O, and
Quote
Prior to Windows 10, version 2004, this function affects a global Windows setting. For all processes Windows uses the lowest value (that is, highest resolution) requested by any process. Starting with Windows 10, version 2004, this function no longer affects global timer resolution. For processes which call this function, Windows uses the lowest value (that is, highest resolution) requested by any process. For processes which have not called this function, Windows does not guarantee a higher resolution than the default system resolution.
So maybe 440bx is running an version prior to Win10-2004 and some other program already has set TimeBeginPeriod to 1. And because it used to be a global setting the fpc test program benefits from that  :D
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 14, 2022, 11:22:33 am
Putting in this in the example also works to make it faster.

Code: Pascal  [Select][+][-]
  1.  TimeBeginPeriod(1);

Quote
ms : 1 repeat count 1000
Total time: 1.890s

ms : 8 repeat count 1000
Total time: 8.581s

ms : 16 repeat count 1000
Total time: 16.752s

Now to find the permanent setting for this  :P
Yes, actually the NtXXX functions should not be called at all, these are the internal kernel calls in windows and are neither documented on MSDN nor guaranteed to be API stable. Either ExSetTimerResolution (https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exsettimerresolution) or TimeBeginPeriod (unit MMSystem if one is searching for it) should be used, which then do the actual kernel call in the background.
It's actually one of microsofts greatest problems with backwards compatebility that some applications use the non documented kernel APIs, even though they shouldn't, and when MS changes them in a new version, suddenly a few thousand systems of paying customers break who blame MS for this. But this is another story. Just for anyone who wishes to tinker with these timers in production, don't use NtSetTimerResolution

O, and
Quote
Prior to Windows 10, version 2004, this function affects a global Windows setting. For all processes Windows uses the lowest value (that is, highest resolution) requested by any process. Starting with Windows 10, version 2004, this function no longer affects global timer resolution. For processes which call this function, Windows uses the lowest value (that is, highest resolution) requested by any process. For processes which have not called this function, Windows does not guarantee a higher resolution than the default system resolution.
So maybe 440bx is running an version prior to Win10-2004 and some other program already has set TimeBeginPeriod to 1. And because it used to be a global setting the fpc test program benefits from that  :D
I was already wondering why this setting does not affect other processes :)
Title: Re: cannot receive messages; udp server with lnet
Post by: 440bx on July 14, 2022, 12:00:23 pm
Maybe I'm going to disappoint someone but, I don't have an "exotic" CPU, just a simple I7 860.

I don't have an "exotic" version of Windows either, just Win 7 SP1, obtained from MS.

There is nothing exotic about the motherboard either, it's a run of the mill ASUS.

My copy of VMware is also from VMware, a bit old by now, 2015.

The one thing that is possible, is that VMware sets the timer resolution upon starting and (this is speculation on my part but, based on what @paweld mentitoned, it seems to be a possibility), since I'm always running VMs (my development "machine" is a VM), I wouldn't notice it.

Whatever the case may be, MS has never been clear about how the Windows scheduler carries out its functions.  This is a quote from the description of Sleep (emphasis mine):
Quote
The system clock "ticks" at a constant rate. If dwMilliseconds is less than the resolution of the system clock, the thread may sleep for less than the specified length of time.
Whenever I've paid some attention to the interval, so far, I am yet to see an instance where the thread would sleep for _less_ than the specified time. As a result, I take that claim from MS with a grain of salt (and just about everything else it says about Sleep.)

Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 14, 2022, 12:55:23 pm
You are right, that is defenetly not an exotic CPU.
If you are using Hyper-V VMs than this could be the issue, because this is where I have the exact same behavior when starting a Hyper-V VM.
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 14, 2022, 01:01:39 pm
If you are using Hyper-V VMs than this could be the issue, because this is where I have the exact same behavior when starting a Hyper-V VM.
In my Hyper-V Win10, (checking version... 21H2, so later than 2004) I still have long sleep(1) of 15ms.

Not sure why you have faster results in your Hyper-V.

Is there a method to query the current setting/value (the one which TimeBeginPeriod changes)??
Maybe some default setting in registry or otherwise is set.
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 14, 2022, 01:17:40 pm
Maybe with ExSetTimerResolution (thin wrapper around the NT call): https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exsettimerresolution if SetResolution is false it should return the current resolution
Title: Re: cannot receive messages; udp server with lnet
Post by: PascalDragon on July 14, 2022, 01:24:59 pm
Maybe with ExSetTimerResolution (thin wrapper around the NT call): https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exsettimerresolution if SetResolution is false it should return the current resolution

Ex* functions are only available from kernel mode. Either use what is provided from the Windows API or use the Nt* function (despite not documented they're very stable as well).
Title: Re: cannot receive messages; udp server with lnet
Post by: Warfley on July 14, 2022, 01:58:50 pm
Ah you are right, I confused them with the FunctioNameEx functions.
The API for this is https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timegetdevcaps
Title: Re: cannot receive messages; udp server with lnet
Post by: rvk on July 14, 2022, 02:22:17 pm
Ah you are right, I confused them with the FunctioNameEx functions.
The API for this is https://docs.microsoft.com/en-us/windows/win32/api/timeapi/nf-timeapi-timegetdevcaps
The TimeGetDevCaps only shows the min and max value. Not the current value.

Code: Pascal  [Select][+][-]
  1. _timecaps = packed Record
  2.   wPeriodMin: UINT;
  3.   wPeriodMax: UINT;
  4. end;

This doesn't give me a different value after doing TimeBeginPeriod(1), which I would expect because it does fix the sleep(1).

Code: Pascal  [Select][+][-]
  1. var
  2.   TCaps: TTimeCaps; // WinAPI.MMSystem;
  3.   rc: MMResult;
  4.  
  5. begin
  6.  
  7.   rc := timeGetDevCaps(@TCaps, SizeOf(TCaps)); // WinAPI.MMSystem;
  8.   if rc = 0
  9.    then Writeln(Format('Min %d / Max %d', [TCaps.wPeriodMin, TCaps.wPeriodMax]))
  10.     else Writeln(Format('timeGetDevCaps returned %d', [rc]));
  11.  
  12.   TimeBeginPeriod(1);
  13.  
  14.   rc := timeGetDevCaps(@TCaps, SizeOf(TCaps)); // WinAPI.MMSystem;
  15.   if rc = 0
  16.    then Writeln(Format('Min %d / Max %d', [TCaps.wPeriodMin, TCaps.wPeriodMax]))
  17.     else Writeln(Format('timeGetDevCaps returned %d', [rc]));

Quote
Min 1 / Max 1000000
Min 1 / Max 1000000

Title: Re: cannot receive messages; udp server with lnet
Post by: SymbolicFrank on July 18, 2022, 10:44:41 am
Yes, that clockres program and the powercfg report are very interesting. And it nicely explains why it is so inconsistent:

- It depends on which application has set the lowest timer.
- It is rounded up or down from the last timer tick.
- Some Windows versions try to emulate a slower timer by waiting approximately 15.6 ms by skipping interrupts. That also means that they're not running in sync.
- Some Linuxes use a free running scheduler, which impacts VM's.

In short: it depends. Don't count on it taking a specific time.


Btw. The only good way to measure time in such cases is by using the functions that return the current CPU cycle count. Or an external RTC.

On second thought: the CPU cycle count depends on the power saving, so an external clock source is the only reliable way.
TinyPortal © 2005-2018