JohnLM 14 Posted August 4, 2023 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
DelphiUdIT 176 Posted August 5, 2023 (edited) 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 August 5, 2023 by DelphiUdIT Share this post Link to post
Angus Robertson 574 Posted August 5, 2023 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 2 Share this post Link to post
DelphiUdIT 176 Posted August 5, 2023 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. 1 Share this post Link to post
Angus Robertson 574 Posted August 5, 2023 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
DelphiUdIT 176 Posted August 5, 2023 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
Angus Robertson 574 Posted August 5, 2023 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 1 1 Share this post Link to post
Remy Lebeau 1396 Posted August 6, 2023 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; 1 1 Share this post Link to post
DelphiUdIT 176 Posted August 6, 2023 (edited) 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 August 6, 2023 by DelphiUdIT Share this post Link to post
JohnLM 14 Posted August 7, 2023 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
DelphiUdIT 176 Posted August 7, 2023 (edited) 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 August 7, 2023 by DelphiUdIT Share this post Link to post
JohnLM 14 Posted August 7, 2023 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. Share this post Link to post
Patrick PREMARTIN 74 Posted August 8, 2023 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
Remy Lebeau 1396 Posted August 8, 2023 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
JohnLM 14 Posted August 8, 2023 @ 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
JohnLM 14 Posted August 8, 2023 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
Remy Lebeau 1396 Posted August 8, 2023 (edited) 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 August 8, 2023 by Remy Lebeau Share this post Link to post