Jump to content
JohnLM

What is the recommended method of obtaining my devices IP address?

Recommended Posts

Delphi XE7 / 11.2, Windows 7, tablets(Android 4.4.) and phones (Android 11 and 12)

 

I am searching around but have not found the answer.  I am looking for obtaining the IP address of all my devices, but I want to do it through code

 

I would like to test different ideas around with sending plain Text and Stream data to all my devices. I have a several laptops, tablets and mobile phones (android). 

 

Is this possible?  TIA.

Share this post


Link to post

You can use Indy to find local addresses of every device. You can send these lists wherever you want.
This is an example:

uses IdStack,
     IdStackWindows;  //<--- This is for Windows, but I think you can use others Units for others platforms (IdStacklibc, IdStackLinux, IdStack......)

function GetLocalIpList(Name: string): TStringList;
var Lista: TIdStackLocalAddressList;
    temp: TCollectionItem;
    GProva: TIdStackWindows;
begin
  result := TStringList.Create;
  try
    Lista := TIdStackLocalAddressList.Create;
    GProva := TIdStackWindows.Create;
    GProva.GetLocalAddressList(Lista);
    for temp in Lista do
      if temp is TIdStackLocalAddressIPv4 then
        result.add((temp as TIdStackLocalAddressIPv4).IPAddress);
    GProva.Free;
    Lista.Free;
  except on e:exception do
     ;
  end;
end;

 

Edited by DelphiUdIT

Share this post


Link to post

If you mean all the local IP addresses on your LAN, ICS has a new component TIcsNeighbDevices that builds a historic LAN neighbourhood MAC device and IPv4 and IPv6 address table using ARP, neighbourhood discovery and network scanning.  There is a new sample OverbyteIcsNetTools.dpr that illustrates its use. 

 

Angus

 

  • Like 2

Share this post


Link to post

Another solution could be to create a simple UDP server with Indy on port x and use the UDP broadcast to send a packet (perhaps containing the list mentioned in my previous post). Obviously this solution works only on local networks. Each device connected to the LAN would receive that packet on port X from which you can detect both the "remote" address and possibly read the UDP packet data.

  • Like 1

Share this post


Link to post
Quote

Another solution could be to create a simple UDP server with Indy on port x and use the UDP broadcast to send a packet

That is what the ARP protocol does, except your version requires software running on every device and for those devices to be running.

 

Angus

Share this post


Link to post
35 minutes ago, Angus Robertson said:

That is what the ARP protocol does, except your version requires software running on every device and for those devices to be running.

 

Angus

Yes, i know that. But arp implemented is very slowly (in some networks needs 15 minutes to be updated). In my solution you may have the knowledge immediately, of course like you told if there is the software running.

Other way is to replicate the arp discovery for IPV4 (RFC826) scanning the whole net and do it more "fast". Of course one must implemented the NDP for IPV6 (RFC4861).

But this means that you must run other software too.

 

Bye

Share this post


Link to post
Quote

Other way is to replicate the arp discovery for IPV4 (RFC826) scanning the whole net and do it more "fast". Of course one must implemented the NDP for IPV6 (RFC4861).

Both of which are done by the new ICS component TIcsNeighbDevices which gives a similar display to the two Nirsoft scanner tools. 

 

Angus

 

  • Like 1
  • Thanks 1

Share this post


Link to post
16 hours ago, DelphiUdIT said:

You can use Indy to find local addresses of every device.

What you describe gets the local IPs of the device that your code is running it.  It does not get the IPs of other devices on the local network.

16 hours ago, DelphiUdIT said:

uses
  IdStack,
  IdStackWindows; //<--- This is for Windows, but I think you can use others Units for others platforms (IdStacklibc, IdStackLinux, IdStack......)

 

You don't need to use the IdStackXXX units directly in this example, just the base IdStack unit by itself will suffice.  The correct way to use TIdStack methods is to call them on the global GStack object.  Indy can instantiate the correct derived class for you based on the local OS platform, eg:

uses
  IdGlobal, IdStack;

function GetLocalIpList(Name: string): TStringList;
var
  Lista: TIdStackLocalAddressList;
  temp: TIdStackLocalAddress;
  I: Integer;
begin
  Result := TStringList.Create;
  try
    TIdStack.IncUsage; // instantiates GStack if needed...
    try
      Lista := TIdStackLocalAddressList.Create;
      try
        GStack.GetLocalAddressList(Lista);
        for I := 0 to Lista.Count-1 do begin
          temp := Lista[I];
          if temp.IPVersion = Id_IPv4 then
            Result.add(temp.IPAddress);
        end;
      finally
        Lista.Free;
      end;
    finally
      TIdStack.DecUsage; // frees GStack if needed...
    end;
  except
    Result.Free;
    raise;
  end;
end;

 

  • Like 1
  • Thanks 1

Share this post


Link to post
7 hours ago, Remy Lebeau said:

What you describe gets the local IPs of the device that your code is running it.  It does not get the IPs of other devices on the local network.

Yes, that's exactly what I meant. In the second post I indicated how to transmit these information in a simple way.
I use this to keep track of the IPs assigned to all systems (individual processing industrial line). So I can also know and monitor the IPs assigned to the various NICs (each PC has 4/5 NICs and about 8 IPv4 addresses). Otherwise I wouldn't know how to get such data from a PC on the network (except using SNMP).

 

7 hours ago, Remy Lebeau said:

You don't need to use the IdStackXXX units directly in this example, just the base IdStack unit by itself will suffice.  The correct way to use TIdStack methods is to call them on the global GStack object.  Indy can instantiate the correct derived class for you based on the local OS platform, eg:

Thanks very much for the suggestion. Really appreciated.

Edited by DelphiUdIT

Share this post


Link to post

Update on this endeavor. . .

 

Yesterday, I compiled the two code snippets (from both DelphiUdIT and Remy) into an app, and both work.  Then I compiled and made several apps under Windows 7 (VCL and FMX apps) and Android, in both Delphi XE7 Pro and Delphi 11.2 Alexandria.

 

The IP numbers I received so far are (10.0.0.3 laptop) and (127.0.0.1 cellphone).

 

Now, depending on when I connect and disconnect the USB cable from my Windows laptop to my cellphone, I will get different IP numbers.  So, for example, the following is what I receive in that test app: 

 

USB cable Connected

* Windows app -- (192.168.nn.nnn) and (10.0.0.3) where n is a 2-to-3 digit number,

* Phone s10+ -- (127.0.0.1) 

 

USB cable Disconnected

* Windows app -- (10.0.0.3) 

* Phone s10+ -- (127.0.0.1) 

Share this post


Link to post

That may be right. The USB when is inserted and connected take 192.168.xx.xxx, and there is another NIC adapter that has the 10.0.0.3. That may be also a VM virtual adapter (like VirtualBox or VMWare). In Windows 11 there is the virtual IP for WSL too.

 

In the Phone 127.0.0.1 is a localhost IP. I don't know in Android if there should be an IP with USB cable.

 

Bye

Edited by DelphiUdIT

Share this post


Link to post

The USB cable part is a new situation.  I never use to get a pop-up for it to configure it for the network.  I used to plug it the cable in the laptop and phone and that was it.

 

Due to the nature of unexplained issues way back in the XE7 days of mobile development, I decided not to allow the pop-up to auto-accept and never pop up. I wanted to make sure that I had a true connection to each device, each time I connected the cable. 

 

But, until recently, and I don't remember exactly when or why, on one day this past July/2023, when I plugged in the USB cable that it started to pop-up a network dialog box with three options to choose to setup with, (home, work, or public) and ask me which one I wanted for that session at the time of plug-in, as seen below. This started when I was debugging and reinstalling Bluetooth support on this laptop this past July. 

 

600844104_08072023mon0548pm-SetNetworkLocation-wheniplugintheusbcabeltolaptopandphone.thumb.png.b2210cd8b6ede394843c27c756282a3e.png

Share this post


Link to post

Or you can use "Bonjour" (or uPnP) to publish your service over the network and find it, because as I suppose your question is how to find computers where your program is launched to communicate between devices.

 

Share this post


Link to post
20 hours ago, JohnLM said:

The IP numbers I received so far are (10.0.0.3 laptop) and (127.0.0.1 cellphone).

You didn't say which code you used for which scenario.  Indy's GetLocalAddressList() has a known issue where it reports only 127.0.0.1 on Android.

Share this post


Link to post

@ Remy - for the one that reports 127.0.0.1, that was from the XE7 Pro compile.  

 

I've also ported that to D11.2 Pro, so I will report back what it produces.  

 

Note, the only code that works for Android is yours, and that is the one that I am using for mobile. 

Share this post


Link to post

Update. . .  Remy, I am getting 127.0.0.1 on Android with your code, compiled in Delphi 11.2 Alexandria. 

 

Note, I compiled for both my Galaxy phones, the A01 (32bit) and S10+ (64bit), and both report 127.0.0.01 on them. 

 

{
  creation 8-8-2023 tue

  purpose - to obtain the IP addresses of all devices
}

unit Unit1;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Memo.Types,
  FMX.StdCtrls, FMX.ScrollBox, FMX.Memo, FMX.Controls.Presentation, FMX.Edit,
  IdGlobal, IdStack;

type
  TForm1 = class(TForm)
    eb1: TEdit;
    m1: TMemo;
    btnGet: TButton;
    btnGetRemy: TButton;
    ToolBar1: TToolBar;
    Label1: TLabel;
    Memo1: TMemo;
    procedure btnGetRemyClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}
{$R *.LgXhdpiPh.fmx ANDROID}

// remy's code
function GetLocalIpList2(Name: string): TStringList;
var
  Lista: TIdStackLocalAddressList;
  temp: TIdStackLocalAddress;
  I: Integer;
begin
  Result := TStringList.Create;
  try
    TIdStack.IncUsage; // instantiates GStack if needed...
    try
      Lista := TIdStackLocalAddressList.Create;
      try
        GStack.GetLocalAddressList(Lista);
        for I := 0 to Lista.Count-1 do begin
          temp := Lista[I];
          if temp.IPVersion = Id_IPv4 then
            Result.add(temp.IPAddress);
        end;
      finally
        Lista.Free;
      end;
    finally
      TIdStack.DecUsage; // frees GStack if needed...
    end;
  except
    Result.Free;
    raise;
  end;
end;

procedure TForm1.btnGetRemyClick(Sender: TObject);
begin
  m1.Lines := GetLocalIpList2('');
end;

end.

 

Share this post


Link to post
1 hour ago, JohnLM said:

procedure TForm1.btnGetRemyClick(Sender: TObject);
begin
  m1.Lines := GetLocalIpList2('');
end;

 

Not related to the 127.0.0.1 issue - note that the code above will leak the returned TStringList on mobile platforms in Delphi 10.4 and later, as ARC is no longer being used for object lifetime management, so you need to Free() the list when you are done using it on all platforms, eg:

procedure TForm1.btnGetRemyClick(Sender: TObject);
var
  IPs: TStringList;
begin
  IPs := GetLocalIpList2('');
  try
    m1.Lines := IPs;
  finally
    IPs.Free;
  end;
end;

A better option is to pass in the target TStrings as a parameter and let the function add to it as needed, eg:

procedure GetLocalIpList2(Name: string; IPList: TStrings);
var
  ...
begin
  ...
  IPList.BeginUpdate;
  try
    ...
    IPList.Add(...);
    ...
  finally
    IPList.EndUpdate;
  end;
  ...
end;

procedure TForm1.btnGetRemyClick(Sender: TObject);
begin
  GetLocalIpList2('', m1.Lines);
end;

 

Edited by Remy Lebeau

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×