TIdIPWatch returns 空白 IP(与 TIdStack 一样)
TIdIPWatch returns blank IP (as does TIdStack)
我正在寻找 Lazarus/FPC 中获取本地 IP 地址的简单解决方案,当然 INDY 似乎最简单。这是在 2015 MBP 上的并行 MacOS VM 运行 Mojave 运行 上。我正在使用 Lazarus 2.0.0RC3,代码在 DYLIB 中。我需要本地机器的 IP 地址来获取它的 MAC 地址。
我正在使用 TIdWatch
,它应该只是 return 本地 IP 地址(来自其 CurrentIP
属性)。我喜欢这两种解决方案,IdStack
下面会详细介绍,因为代码非常简单,但是当然,如果代码不起作用,再简单也没有任何好处:
uses
IdBaseComponent,
IdComponent,
IdIPWatch,
...
function getLocalIP: string;
var
IPW: TIdIPWatch;
begin
IpW := TIdIPWatch.Create(nil);
try
if IpW.LocalIP <> '' then
Result := IpW.LocalIP;
ShowMessage('IP: ' + Result);
finally
IpW.Free;
end;
end;
实际IP地址是192.168.1.25,但是调用IdPWatch.LocalIP
return是一个空字符串。
我尝试将 Active
设置为 True (IpW.Active := True;
),但这只会终止应用程序(我不确定为什么,它只是突然终止)。
同样,我尝试使用 IdStack
并遇到同样的问题,即。它 Returns 一个空字符串:
uses
IdStack,
...
function GetLocalIP : String;
begin
TIdStack.IncUsage;
try
Result := GStack.LocalAddress;
ShowMessage('IP: ' + Result);
finally
TIdStack.DecUsage;
end;
end;
同样,此代码来自互联网,但我已经查找了 IdStack
和 TIdIPWatch
的文档,根据我的阅读,应该 return 本地 IP 地址如 Lazarus 网站所述。
编辑:
根据 Remy 的评论,我修改了函数以使用 GStack.GetLocalAddressList 函数,而不是我之前使用的已弃用函数。请注意,结果是相同的,并且 IPList(TIdStackLocalAddressList 变量)没有元素:
function getLocalIP: string;
var
IPList: TIdStackLocalAddressList;
IPStrings: TStringList;
i: integer;
begin
try
try
Result:='';
IPList:=TIdStackLocalAddressList.Create;
IPStrings := TStringList.create;
TIdStack.IncUsage;
GStack.GetLocalAddressList(IPList);
if IPList.count > 0 then
begin
WriteLog('DEBUG', 'No of Addresses: ' + inttostr(IPList.count));
for i := 0 to IPList.Count - 1 do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
IPStrings.Add(IPList[i].IPAddress+':'+ TIdStackLocalAddressIPv4(IPList[i]).SubNetMask);
end;
end;
// show IP Addresses in the log file
if IPStrings.Count > 0 then
begin
for i := 0 to IPStrings.Count -1 do
WriteLog('DEBUG', 'IP Address #' + inttostr(i) + ': ' + IPStrings[i]);
Result := IPStrings[0];
WriteLog('DEBUG', 'IP: ' + Result);
end
else
WriteLog('DEBUG', 'IPStrings has no entries');
end
else
WriteLog('DEBUG', 'TIdStackLocalAddressList has no entries');
except
On E:Exception do
begin
Result := '';
WriteLog('ERROR', 'IP Error: ' + E.message);
end;
end;
finally
TIdStack.DecUsage;
end;
end;
所以我的问题是:
我可以在Lazarus/FPC中使用TIdIPWatch
或TIdStack
来查找虚拟机的本地IP地址吗?
任何人都可以看到我 post 阻止 return 本地 IP 地址的代码片段中的任何明显错误吗?
我很乐意 post 更多代码,如果您觉得我遗漏了任何问题,我会回答任何问题。
编辑2:
所以 INDY 和其他方法都设置为使用 ifconfig 来获取 IP 地址。解决方案似乎在寻找 'net Add:'
在 MacOS Mojave 10.14 中,IfConfig 不会 return 'net Addr:'。它只是 returns 'net',至少在我的 Parallels VM 中是这样。您可能希望相应地调整代码。请注意 VM 和物理系统的输出似乎不同:
我的 Mojave Parallels VM 系统的典型输出(<> 填充块引用):
kevin$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
UHC29: flags=0<> mtu 0
EHC253: flags=0<> mtu 0
XHC221: flags=0<> mtu 0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4>
ether 00:1c:42:72:74:a3
inet6 fe80::3a:650d:9b24:c9c5%en0 prefixlen 64 secured scopeid 0x7
inet 192.168.1.25 netmask 0xffffff00 broadcast 192.168.1.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
硬件系统的典型输出运行 Mojave(实际IP地址为en0(5),网络地址):
kevin$ ifconfig
awdl0 (8):
flags UP BROADCAST RUNNING PROMISC SIMPLEX MULTICAST
mtu 1484
bridge0 (10):
flags UP BROADCAST NOTRAILERS RUNNING SIMPLEX MULTICAST
mtu 1500
en0 (5):
inet address 192.168.1.167
netmask 255.255.255.0
broadcast 192.168.1.255
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
en1 (7):
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
en2 (9):
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
lo0 (1):
inet address 127.0.0.1
netmask 255.0.0.0
flags UP LOOPBACK RUNNING MULTICAST
mtu 16384
p2p0 (6):
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 2304
utun0 (11):
flags UP POINTOPOINT RUNNING MULTICAST
mtu 2000
utun1 (12):
flags UP POINTOPOINT RUNNING MULTICAST
mtu 1380
vnic0 (13):
inet address 10.211.55.2
netmask 255.255.255.0
broadcast 10.211.55.255
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 1500
vnic1 (14):
inet address 10.37.129.2
netmask 255.255.255.0
broadcast 10.37.129.255
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 1500
底线是什么,这很令人困惑。在 VM 上您需要搜索 'inet ',在硬系统上您需要搜索 'inet address '。现在我首先承认'not a doctor',这不是我的专业领域。所以我不确定 INDY 10 是否正在搜索 'inet:' and/or 'inet address:' 末尾有冒号。如果是这样就可以解释为什么它不起作用。我会进一步调查。
GStack.GetLocalAddressList()
是为 OSX 实现的,所以我不能说为什么它不返回任何 IP 地址。您只需要使用调试器进入 Indy 的源代码并找出实际发生故障的位置。在内部,它应该调用 OSX getifaddrs()
资金从 OS 获取 IP 地址。也许该功能在您的 VM 中不起作用。
附带说明一下,您的代码不是很 exception-safe。 IncUsage/DecUsage
、Create/Free
等内容应该包装在单独的 try/finally
块中,而不是按照您的方式进行包装(即 IncUsage
之前的异常会导致 DecUsage
被调用,使引用计数不平衡)。你正在泄漏内存。
您的代码应该更像这样:
function getLocalIP: string;
var
IPList: TIdStackLocalAddressList;
IPStrings: TStringList;
i: integer;
begin
Result := '';
try
IPList := TIdStackLocalAddressList.Create;
try
TIdStack.IncUsage;
try
GStack.GetLocalAddressList(IPList);
finally
TIdStack.DecUsage;
end;
if IPList.Count > 0 then
begin
WriteLog('DEBUG', 'No of Addresses: ' + IntToStr(IPList.Count));
IPStrings := TStringList.Create;
try
for i := 0 to IPList.Count - 1 do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
IPStrings.Add(IPList[i].IPAddress + ':' + TIdStackLocalAddressIPv4(IPList[i]).SubNetMask);
end;
end;
// show IP Addresses in the log file
if IPStrings.Count > 0 then
begin
for i := 0 to IPStrings.Count -1 do
WriteLog('DEBUG', 'IP Address #' + IntToStr(i) + ': ' + IPStrings[i]);
Result := IPStrings[0];
WriteLog('DEBUG', 'IP: ' + Result);
end else
WriteLog('DEBUG', 'IPStrings has no entries');
finally
IPStrings.Free;
end;
end else
WriteLog('DEBUG', 'TIdStackLocalAddressList has no entries');
finally
IPList.Free;
end;
except
On E: Exception do
begin
Result := '';
WriteLog('ERROR', 'IP Error: ' + E.message);
end;
end;
end;
我正在寻找 Lazarus/FPC 中获取本地 IP 地址的简单解决方案,当然 INDY 似乎最简单。这是在 2015 MBP 上的并行 MacOS VM 运行 Mojave 运行 上。我正在使用 Lazarus 2.0.0RC3,代码在 DYLIB 中。我需要本地机器的 IP 地址来获取它的 MAC 地址。
我正在使用 TIdWatch
,它应该只是 return 本地 IP 地址(来自其 CurrentIP
属性)。我喜欢这两种解决方案,IdStack
下面会详细介绍,因为代码非常简单,但是当然,如果代码不起作用,再简单也没有任何好处:
uses
IdBaseComponent,
IdComponent,
IdIPWatch,
...
function getLocalIP: string;
var
IPW: TIdIPWatch;
begin
IpW := TIdIPWatch.Create(nil);
try
if IpW.LocalIP <> '' then
Result := IpW.LocalIP;
ShowMessage('IP: ' + Result);
finally
IpW.Free;
end;
end;
实际IP地址是192.168.1.25,但是调用IdPWatch.LocalIP
return是一个空字符串。
我尝试将 Active
设置为 True (IpW.Active := True;
),但这只会终止应用程序(我不确定为什么,它只是突然终止)。
同样,我尝试使用 IdStack
并遇到同样的问题,即。它 Returns 一个空字符串:
uses
IdStack,
...
function GetLocalIP : String;
begin
TIdStack.IncUsage;
try
Result := GStack.LocalAddress;
ShowMessage('IP: ' + Result);
finally
TIdStack.DecUsage;
end;
end;
同样,此代码来自互联网,但我已经查找了 IdStack
和 TIdIPWatch
的文档,根据我的阅读,应该 return 本地 IP 地址如 Lazarus 网站所述。
编辑:
根据 Remy 的评论,我修改了函数以使用 GStack.GetLocalAddressList 函数,而不是我之前使用的已弃用函数。请注意,结果是相同的,并且 IPList(TIdStackLocalAddressList 变量)没有元素:
function getLocalIP: string;
var
IPList: TIdStackLocalAddressList;
IPStrings: TStringList;
i: integer;
begin
try
try
Result:='';
IPList:=TIdStackLocalAddressList.Create;
IPStrings := TStringList.create;
TIdStack.IncUsage;
GStack.GetLocalAddressList(IPList);
if IPList.count > 0 then
begin
WriteLog('DEBUG', 'No of Addresses: ' + inttostr(IPList.count));
for i := 0 to IPList.Count - 1 do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
IPStrings.Add(IPList[i].IPAddress+':'+ TIdStackLocalAddressIPv4(IPList[i]).SubNetMask);
end;
end;
// show IP Addresses in the log file
if IPStrings.Count > 0 then
begin
for i := 0 to IPStrings.Count -1 do
WriteLog('DEBUG', 'IP Address #' + inttostr(i) + ': ' + IPStrings[i]);
Result := IPStrings[0];
WriteLog('DEBUG', 'IP: ' + Result);
end
else
WriteLog('DEBUG', 'IPStrings has no entries');
end
else
WriteLog('DEBUG', 'TIdStackLocalAddressList has no entries');
except
On E:Exception do
begin
Result := '';
WriteLog('ERROR', 'IP Error: ' + E.message);
end;
end;
finally
TIdStack.DecUsage;
end;
end;
所以我的问题是:
我可以在Lazarus/FPC中使用
TIdIPWatch
或TIdStack
来查找虚拟机的本地IP地址吗?任何人都可以看到我 post 阻止 return 本地 IP 地址的代码片段中的任何明显错误吗?
我很乐意 post 更多代码,如果您觉得我遗漏了任何问题,我会回答任何问题。
编辑2:
所以 INDY 和其他方法都设置为使用 ifconfig 来获取 IP 地址。解决方案似乎在寻找 'net Add:'
在 MacOS Mojave 10.14 中,IfConfig 不会 return 'net Addr:'。它只是 returns 'net',至少在我的 Parallels VM 中是这样。您可能希望相应地调整代码。请注意 VM 和物理系统的输出似乎不同:
我的 Mojave Parallels VM 系统的典型输出(<> 填充块引用):
kevin$ ifconfig
lo0: flags=8049<UP,LOOPBACK,RUNNING,MULTICAST> mtu 16384
options=1203<RXCSUM,TXCSUM,TXSTATUS,SW_TIMESTAMP>
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
nd6 options=201<PERFORMNUD,DAD>
gif0: flags=8010<POINTOPOINT,MULTICAST> mtu 1280
stf0: flags=0<> mtu 1280
UHC29: flags=0<> mtu 0
EHC253: flags=0<> mtu 0
XHC221: flags=0<> mtu 0
en0: flags=8863<UP,BROADCAST,SMART,RUNNING,SIMPLEX,MULTICAST> mtu 1500
options=2b<RXCSUM,TXCSUM,VLAN_HWTAGGING,TSO4>
ether 00:1c:42:72:74:a3
inet6 fe80::3a:650d:9b24:c9c5%en0 prefixlen 64 secured scopeid 0x7
inet 192.168.1.25 netmask 0xffffff00 broadcast 192.168.1.255
nd6 options=201<PERFORMNUD,DAD>
media: autoselect (1000baseT <full-duplex>)
硬件系统的典型输出运行 Mojave(实际IP地址为en0(5),网络地址):
kevin$ ifconfig
awdl0 (8):
flags UP BROADCAST RUNNING PROMISC SIMPLEX MULTICAST
mtu 1484
bridge0 (10):
flags UP BROADCAST NOTRAILERS RUNNING SIMPLEX MULTICAST
mtu 1500
en0 (5):
inet address 192.168.1.167
netmask 255.255.255.0
broadcast 192.168.1.255
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
en1 (7):
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
en2 (9):
flags UP BROADCAST NOTRAILERS RUNNING PROMISC SIMPLEX MULTICAST
mtu 1500
lo0 (1):
inet address 127.0.0.1
netmask 255.0.0.0
flags UP LOOPBACK RUNNING MULTICAST
mtu 16384
p2p0 (6):
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 2304
utun0 (11):
flags UP POINTOPOINT RUNNING MULTICAST
mtu 2000
utun1 (12):
flags UP POINTOPOINT RUNNING MULTICAST
mtu 1380
vnic0 (13):
inet address 10.211.55.2
netmask 255.255.255.0
broadcast 10.211.55.255
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 1500
vnic1 (14):
inet address 10.37.129.2
netmask 255.255.255.0
broadcast 10.37.129.255
flags UP BROADCAST RUNNING SIMPLEX MULTICAST
mtu 1500
底线是什么,这很令人困惑。在 VM 上您需要搜索 'inet ',在硬系统上您需要搜索 'inet address '。现在我首先承认'not a doctor',这不是我的专业领域。所以我不确定 INDY 10 是否正在搜索 'inet:' and/or 'inet address:' 末尾有冒号。如果是这样就可以解释为什么它不起作用。我会进一步调查。
GStack.GetLocalAddressList()
是为 OSX 实现的,所以我不能说为什么它不返回任何 IP 地址。您只需要使用调试器进入 Indy 的源代码并找出实际发生故障的位置。在内部,它应该调用 OSX getifaddrs()
资金从 OS 获取 IP 地址。也许该功能在您的 VM 中不起作用。
附带说明一下,您的代码不是很 exception-safe。 IncUsage/DecUsage
、Create/Free
等内容应该包装在单独的 try/finally
块中,而不是按照您的方式进行包装(即 IncUsage
之前的异常会导致 DecUsage
被调用,使引用计数不平衡)。你正在泄漏内存。
您的代码应该更像这样:
function getLocalIP: string;
var
IPList: TIdStackLocalAddressList;
IPStrings: TStringList;
i: integer;
begin
Result := '';
try
IPList := TIdStackLocalAddressList.Create;
try
TIdStack.IncUsage;
try
GStack.GetLocalAddressList(IPList);
finally
TIdStack.DecUsage;
end;
if IPList.Count > 0 then
begin
WriteLog('DEBUG', 'No of Addresses: ' + IntToStr(IPList.Count));
IPStrings := TStringList.Create;
try
for i := 0 to IPList.Count - 1 do
begin
if IPList[i].IPVersion = Id_IPv4 then
begin
IPStrings.Add(IPList[i].IPAddress + ':' + TIdStackLocalAddressIPv4(IPList[i]).SubNetMask);
end;
end;
// show IP Addresses in the log file
if IPStrings.Count > 0 then
begin
for i := 0 to IPStrings.Count -1 do
WriteLog('DEBUG', 'IP Address #' + IntToStr(i) + ': ' + IPStrings[i]);
Result := IPStrings[0];
WriteLog('DEBUG', 'IP: ' + Result);
end else
WriteLog('DEBUG', 'IPStrings has no entries');
finally
IPStrings.Free;
end;
end else
WriteLog('DEBUG', 'TIdStackLocalAddressList has no entries');
finally
IPList.Free;
end;
except
On E: Exception do
begin
Result := '';
WriteLog('ERROR', 'IP Error: ' + E.message);
end;
end;
end;