77import socket
88import subprocess
99import sys
10+ import threading
1011import time
1112from typing import Any , Dict , List , Optional , Set , Tuple
1213
@@ -1145,26 +1146,11 @@ def _merge_ipv4_detail_fields(base: Dict[str, Any], add: Dict[str, Any]) -> None
11451146
11461147_detail_mono = 0.0
11471148_detail_payload : Dict [str , Any ] = {}
1149+ _detail_snap_lock = threading .Lock ()
11481150
11491151
1150- def get_default_ipv4_detail_snapshot (ttl_sec : float = 20.0 ) -> Dict [str , Any ]:
1151- """
1152- 默认出口网卡的当前 IPv4 参数,供教师端静态表单预填。
1153- 优先用 PowerShell(默认路由 InterfaceIndex,与网卡显示名无关),再用 WMI 补缺;带短时缓存。
1154- """
1155- global _detail_mono , _detail_payload
1156- now = time .monotonic ()
1157- if _detail_payload and (now - _detail_mono ) < ttl_sec :
1158- return dict (_detail_payload )
1159-
1160- if sys .platform != "win32" :
1161- _detail_mono = now
1162- _detail_payload = {}
1163- return {}
1164-
1165- pref = _outbound_ipv4_hint ().strip ()
1166-
1167- out : Dict [str , Any ] = {
1152+ def _empty_ipv4_detail_for_cache () -> Dict [str , Any ]:
1153+ return {
11681154 "ip" : "" ,
11691155 "mask" : "" ,
11701156 "gateway" : "" ,
@@ -1173,54 +1159,92 @@ def get_default_ipv4_detail_snapshot(ttl_sec: float = 20.0) -> Dict[str, Any]:
11731159 "dhcp" : False ,
11741160 }
11751161
1176- psd = _powershell_ipv4_detail_by_default_route ()
1177- if psd :
1178- out .update (psd )
1179-
1180- widx = _wmic_default_route_interface_index ()
1181- if widx is not None :
1182- row = _wmic_nic_configuration_by_interface_index (widx )
1183- if row :
1184- _merge_ipv4_detail_fields (out , _detail_row_to_dict (row , pref ))
1185-
1186- iface_name , _diag = get_default_ipv4_interface_name ()
1187- if iface_name :
1188- if_idx = _wmic_interface_index_for_netconnection_id (iface_name )
1189- if if_idx is not None and (widx is None or if_idx != widx ):
1190- row2 = _wmic_nic_configuration_by_interface_index (if_idx )
1191- if row2 :
1192- _merge_ipv4_detail_fields (out , _detail_row_to_dict (row2 , pref ))
1193-
1194- if not str (out .get ("ip" ) or "" ).strip () and pref :
1195- out ["ip" ] = pref
1196-
1197- hip = str (out .get ("ip" ) or pref ).strip ()
1198- if hip :
1199- need_more = (
1162+
1163+ def get_default_ipv4_detail_snapshot (
1164+ ttl_sec : float = 75.0 ,
1165+ * ,
1166+ recompute_blocking : bool = True ,
1167+ ) -> Dict [str , Any ]:
1168+ """
1169+ 默认出口网卡的当前 IPv4 参数,供教师端静态表单预填。
1170+ 优先用 PowerShell(默认路由 InterfaceIndex,与网卡显示名无关),再用 WMI 补缺;带缓存。
1171+
1172+ recompute_blocking=False:供心跳线程使用;若有其它线程正在全量采集,则立刻返回上一份缓存,
1173+ 避免与「按需查询」(ttl_sec=0) 并行叠加两次 WMI/子进程拖过教师端单次读超时。
1174+ """
1175+ global _detail_mono , _detail_payload
1176+ now = time .monotonic ()
1177+ if _detail_payload and (now - _detail_mono ) < ttl_sec :
1178+ return dict (_detail_payload )
1179+
1180+ if recompute_blocking :
1181+ _detail_snap_lock .acquire ()
1182+ elif not _detail_snap_lock .acquire (blocking = False ):
1183+ return dict (_detail_payload ) if _detail_payload else _empty_ipv4_detail_for_cache ()
1184+ try :
1185+ now2 = time .monotonic ()
1186+ if _detail_payload and (now2 - _detail_mono ) < ttl_sec :
1187+ return dict (_detail_payload )
1188+
1189+ if sys .platform != "win32" :
1190+ _detail_mono = now2
1191+ _detail_payload = {}
1192+ return {}
1193+
1194+ pref = _outbound_ipv4_hint ().strip ()
1195+
1196+ out : Dict [str , Any ] = _empty_ipv4_detail_for_cache ()
1197+
1198+ psd = _powershell_ipv4_detail_by_default_route ()
1199+ if psd :
1200+ out .update (psd )
1201+
1202+ widx = _wmic_default_route_interface_index ()
1203+ if widx is not None :
1204+ row = _wmic_nic_configuration_by_interface_index (widx )
1205+ if row :
1206+ _merge_ipv4_detail_fields (out , _detail_row_to_dict (row , pref ))
1207+
1208+ iface_name , _diag = get_default_ipv4_interface_name ()
1209+ if iface_name :
1210+ if_idx = _wmic_interface_index_for_netconnection_id (iface_name )
1211+ if if_idx is not None and (widx is None or if_idx != widx ):
1212+ row2 = _wmic_nic_configuration_by_interface_index (if_idx )
1213+ if row2 :
1214+ _merge_ipv4_detail_fields (out , _detail_row_to_dict (row2 , pref ))
1215+
1216+ if not str (out .get ("ip" ) or "" ).strip () and pref :
1217+ out ["ip" ] = pref
1218+
1219+ hip = str (out .get ("ip" ) or pref ).strip ()
1220+ if hip :
1221+ need_more = (
1222+ not str (out .get ("mask" ) or "" ).strip ()
1223+ or not str (out .get ("gateway" ) or "" ).strip ()
1224+ or not str (out .get ("dns_primary" ) or "" ).strip ()
1225+ )
1226+ if need_more :
1227+ row_fix = _wmic_nic_configuration_row_for_ipv4 (hip )
1228+ if row_fix :
1229+ _merge_ipv4_detail_fields (out , _detail_row_to_dict (row_fix , hip ))
1230+ if not str (out .get ("gateway" ) or "" ).strip ():
1231+ gw_rp = _route_print_ipv4_default_gateway ()
1232+ if gw_rp :
1233+ out ["gateway" ] = gw_rp
1234+
1235+ idx_netsh = widx
1236+ if idx_netsh is None and iface_name :
1237+ alt_i = _wmic_interface_index_for_netconnection_id (iface_name )
1238+ if alt_i is not None :
1239+ idx_netsh = alt_i
1240+ if idx_netsh is not None and (
12001241 not str (out .get ("mask" ) or "" ).strip ()
1201- or not str (out .get ("gateway" ) or "" ).strip ()
12021242 or not str (out .get ("dns_primary" ) or "" ).strip ()
1203- )
1204- if need_more :
1205- row_fix = _wmic_nic_configuration_row_for_ipv4 (hip )
1206- if row_fix :
1207- _merge_ipv4_detail_fields (out , _detail_row_to_dict (row_fix , hip ))
1208- if not str (out .get ("gateway" ) or "" ).strip ():
1209- gw_rp = _route_print_ipv4_default_gateway ()
1210- if gw_rp :
1211- out ["gateway" ] = gw_rp
1212-
1213- idx_netsh = widx
1214- if idx_netsh is None and iface_name :
1215- alt_i = _wmic_interface_index_for_netconnection_id (iface_name )
1216- if alt_i is not None :
1217- idx_netsh = alt_i
1218- if idx_netsh is not None and (
1219- not str (out .get ("mask" ) or "" ).strip ()
1220- or not str (out .get ("dns_primary" ) or "" ).strip ()
1221- ):
1222- _merge_ipv4_detail_fields (out , _netsh_ipv4_enrich_from_ifindex (idx_netsh ))
1223-
1224- _detail_mono = now
1225- _detail_payload = dict (out )
1226- return dict (out )
1243+ ):
1244+ _merge_ipv4_detail_fields (out , _netsh_ipv4_enrich_from_ifindex (idx_netsh ))
1245+
1246+ _detail_mono = time .monotonic ()
1247+ _detail_payload = dict (out )
1248+ return dict (out )
1249+ finally :
1250+ _detail_snap_lock .release ()
0 commit comments