解析主机名时防止异常
Posted
技术标签:
【中文标题】解析主机名时防止异常【英文标题】:Preventing Exception when resolving Hostname 【发布时间】:2017-06-20 14:05:04 【问题描述】:我正在尝试制作一个扫描网络以查找 ARP 请求并列出所有现有网络设备的应用。目前我使用SharpPcap
和PacketDoNet
。
当根据给定的 IP 解析主机名时,我在解析“未知”主机时得到一个 SocketException
。所以我把它放在了try/catch中。由于我认为这是一种不好的风格(忽略异常),我正在寻找不同的解决方案。
这是一些代码:
// Button for scanning the network
private void btnStartScanningForClients_Click(object sender, RoutedEventArgs e)
// Check for correct interface
// [...]
// Start scanning process
if (!this.netWorkItOut.Startet)
// Dis-/Enable visual controls
// [...]
// Start scanning
var index = this.cbNetworkInterface.SelectedIndex
this.netWorkItOut.StartDevice(index);
this.netWorkItOut.Scanner.StartScanningNetwork(resolveHostnames);
这是控制对象,它持有扫描器、处理事件、接受数据包并将它们放入队列中
public void StartDevice(int deviceIndex)
this.Startet = true;
// [...]
this.Device = WinPcapDeviceList.Instance[deviceIndex];
// Activate Scanner
this.Scanner = new Scanner(this.DeviceInfo);
// Subscribe Events
// [...]
this.Device.Open(DeviceMode.Promiscuous, 1);
this.Device.Filter = "(arp || ip || ip6)";
this.Device.OnPacketArrival += device_OnPacketArrival;
this.Device.StartCapture();
private void device_OnPacketArrival(object sender, CaptureEventArgs e)
//PacketDoNet
Packet packet;
try
packet = Packet.ParsePacket(LinkLayers.Ethernet, e.Packet.Data);
catch (Exception)
return;
if (packet is EthernetPacket)
var arp = ARPPacket.GetEncapsulated(packet);
if (arp != null)
if (this.Scanner.Started)
lock (this.Scanner.PacketQueueARP)
this.Scanner.PacketQueueARP.Add(arp);
这是控制对象和扫描器类。扫描器类处理 ARP 请求并解析主机名
public void StartScanningNetwork(bool resolveHostnames)
// [...]
this.ResolveHostnames = resolveHostnames;
// start worker to listen for ARP packets
this.workerARP = new Thread(WorkerARP);
this.workerARP.Name = "Scanner thread (ARP)";
this.workerARP.Start();
this.Started = true;
private void WorkerARP()
List<IPAddress> processedIps = new List<IPAddress>();
// copy packets from storage queue to thread queue for processing
while (Started)
// [...]
if (this.threadQueueARP.Count > 0)
foreach (var packet in this.threadQueueARP)
// [...]
if (!processedIps.Contains(ip))
// [...]
if (this.ResolveHostnames)
var resolveHostnamesTask = Task.Factory.StartNew(ResolveHostnamesWorker, ip);
// [...]
// [...]
// [...]
private void ResolveHostnamesWorker(object data)
if (data is IPAddress)
var ip = (IPAddress)data;
var hostname = "";
try
hostname = Dns.GetHostEntry(ip).HostName;
catch
// Raise Event for hostname resolved
这一切都与hostname = Dns.GetHostEntry(ip).HostName
这一行有关
那么:通过 Dns.GetHostEntry() 解析 HostEntry 时,如何避免使用 try/catch?如果没有已知主机,是否有一个函数只返回null
?
提前致谢!
【问题讨论】:
【参考方案1】:由于Dns
类的代码在https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/DNS.cs 下可用,您只能从那里使用相关部分。 (当然你要检查你的项目是否可以使用MIT许可)
实现是在抛出异常的方法InternalGetHostByAddress
中。如果查询成功,您可以返回一个值(bool、enum ...)来提供信息。
【讨论】:
【参考方案2】:据我所知,没有像 TryGetHostName() 这样不会引发异常的方法。
但在我看来,捕获异常是很容易理解的。因此,您应该将捕获异常限制在您期望的范围内:
private void ResolveHostnamesWorker(object data)
if (data is IPAddress)
var ip = (IPAddress)data;
var hostname = "";
try
hostname = Dns.GetHostEntry(ip).HostName;
catch(SocketException socketException)
// maybe limit handling based on data in socketException and
// call throw; to rethrow exception if not the expected one
// Raise Event for hostname resolved
【讨论】:
因为捕捉异常是一个耗时的过程,这应该是我最后的选择。但如果似乎没有其他方法,我必须这样做。谢谢你的回答!以上是关于解析主机名时防止异常的主要内容,如果未能解决你的问题,请参考以下文章
使用 postgres_fdw 创建外部表时翻译主机名时出错