解析主机名时防止异常
Preventing Exception when resolving Hostname
我正在尝试制作一个应用程序来扫描网络中的 ARP 请求并列出所有现有的网络设备。目前我使用 SharpPcap
和 PacketDoNet
.
根据给定的 IP 解析主机名时,解析 "unknown" 主机时得到 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);
}
}
}
}
}
这是控制对象和扫描仪class。扫描器 class 处理 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?如果没有已知主机,是否有 return 只是 null
的函数?
提前致谢!
据我所知,没有像 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
}
}
由于 Class Dns
的代码在 https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/DNS.cs 下可用,您只能从那里使用相关部分。 (当然你要检查你的项目是否可以使用MIT license)
实现在抛出异常的方法InternalGetHostByAddress
中。如果查询成功,您可以在那里 return 一个值(bool、enum ...)来提供信息。
我正在尝试制作一个应用程序来扫描网络中的 ARP 请求并列出所有现有的网络设备。目前我使用 SharpPcap
和 PacketDoNet
.
根据给定的 IP 解析主机名时,解析 "unknown" 主机时得到 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);
}
}
}
}
}
这是控制对象和扫描仪class。扫描器 class 处理 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?如果没有已知主机,是否有 return 只是 null
的函数?
提前致谢!
据我所知,没有像 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
}
}
由于 Class Dns
的代码在 https://github.com/Microsoft/referencesource/blob/master/System/net/System/Net/DNS.cs 下可用,您只能从那里使用相关部分。 (当然你要检查你的项目是否可以使用MIT license)
实现在抛出异常的方法InternalGetHostByAddress
中。如果查询成功,您可以在那里 return 一个值(bool、enum ...)来提供信息。