真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

.NET中如何實(shí)現(xiàn)掃描局域網(wǎng)服務(wù)-創(chuàng)新互聯(lián)

小編給大家分享一下.NET中如何實(shí)現(xiàn)掃描局域網(wǎng)服務(wù),相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

創(chuàng)新互聯(lián)長(zhǎng)期為上1000+客戶提供的網(wǎng)站建設(shè)服務(wù),團(tuán)隊(duì)從業(yè)經(jīng)驗(yàn)10年,關(guān)注不同地域、不同群體,并針對(duì)不同對(duì)象提供差異化的產(chǎn)品和服務(wù);打造開(kāi)放共贏平臺(tái),與合作伙伴共同營(yíng)造健康的互聯(lián)網(wǎng)生態(tài)環(huán)境。為烏審企業(yè)提供專業(yè)的網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè)烏審網(wǎng)站改版等技術(shù)服務(wù)。擁有十多年豐富建站經(jīng)驗(yàn)和眾多成功案例,為您定制開(kāi)發(fā)。

在最近負(fù)責(zé)的項(xiàng)目中,需要實(shí)現(xiàn)這樣一個(gè)需求:在客戶端程序中,掃描當(dāng)前機(jī)器所在網(wǎng)段中的所有機(jī)器上是否有某服務(wù)啟動(dòng),并把所有已經(jīng)啟動(dòng)服務(wù)的機(jī)器列出來(lái),供用戶選擇,連接哪個(gè)服務(wù)。注意:這里所說(shuō)的服務(wù)事實(shí)上就是在一個(gè)固定的端口監(jiān)聽(tīng)基于 TCP 協(xié)議的請(qǐng)求的程序或者服務(wù)(如 WCF 服務(wù))。

要實(shí)現(xiàn)這樣的功能,核心的一點(diǎn)就是在得到當(dāng)前機(jī)器同網(wǎng)段的所有機(jī)器的 IP 后,對(duì)每一 IP 發(fā)生 TCP 連接請(qǐng)求,如果請(qǐng)求超時(shí)或者出現(xiàn)其它異常,則認(rèn)為沒(méi)有服務(wù),反之,如果能夠正常連接,則認(rèn)為服務(wù)正常。

經(jīng)過(guò)基本功能的實(shí)現(xiàn)以及后續(xù)的重構(gòu)之后,就有了本文以下的代碼:一個(gè)接口和具體實(shí)現(xiàn)的類(lèi)。需要說(shuō)明的是:在下面的代碼中,先提到接口,再提到具體類(lèi);而在開(kāi)發(fā)過(guò)程中,則是首先創(chuàng)建了類(lèi),然后才提取了接口。之所以要提取接口,原因有二:一是可以支持 IoC控制反轉(zhuǎn);二是將來(lái)如果其它的同類(lèi)需求,可以其于此接口實(shí)現(xiàn)新功能。

一、接口定義

先看來(lái)一下接口:

/// 
 /// 掃描服務(wù)
 /// 
 public interface IServerScanner
 {
 /// 
 /// 掃描完成
 /// 
 event EventHandler> OnScanComplete;
 /// 
 /// 報(bào)告掃描進(jìn)度
 /// 
 event EventHandler OnScanProgressChanged;
 /// 
 /// 掃描端口
 /// 
 int ScanPort { get; set; }
 /// 
 /// 單次連接超時(shí)時(shí)長(zhǎng)
 /// 
 TimeSpan Timeout { get; set; }
 /// 
 /// 返回指定的IP與端口是否能夠連接上
 /// 
 /// 
 /// 
 /// 
 bool IsConnected(IPAddress ipAddress, int port);
 /// 
 /// 返回指定的IP與端口是否能夠連接上
 /// 
 /// 
 /// 
 /// 
 bool IsConnected(string ip, int port);
 /// 
 /// 開(kāi)始掃描
 /// 
 void StartScan();
 }

其中 Timeout 屬性是控制每次連接請(qǐng)求超時(shí)的時(shí)長(zhǎng)。

二、具體實(shí)現(xiàn)

再來(lái)看一下具體實(shí)現(xiàn)類(lèi):

/// 
 /// 掃描結(jié)果
 /// 
 public class ConnectionResult
 {
 /// 
 /// IPAddress 地址
 /// 
 public IPAddress Address { get; set; }
 /// 
 /// 是否可連接上
 /// 
 public bool CanConnected { get; set; }
 }
 /// 
 /// 掃描完成事件參數(shù)
 /// 
 public class ScanCompleteEventArgs
 {
 /// 
 /// 結(jié)果集合
 /// 
 public List Reslut { get; set; }
 }
 /// 
 /// 掃描進(jìn)度事件參數(shù)
 /// 
 public class ScanProgressEventArgs
 {
 /// 
 /// 進(jìn)度百分比
 /// 
 public int Percent { get; set; }
 }
 /// 
 /// 掃描局域網(wǎng)中的服務(wù)
 /// 
 public class ServerScanner : IServerScanner
 {
 /// 
 /// 同一網(wǎng)段內(nèi) IP 地址的數(shù)量
 /// 
 private const int SegmentIpMaxCount = 255;
 private DateTimeOffset _endTime;
 private object _locker = new object();
 private SynchronizationContext _originalContext = SynchronizationContext.Current;
 private List _resultList = new List();
 private DateTimeOffset _startTime;
 /// 
 /// 記錄調(diào)用/完成委托的數(shù)量
 /// 
 private int _totalCount = 0;
 public ServerScanner()
 {
  Timeout = TimeSpan.FromSeconds(2);
 }
 /// 
 /// 當(dāng)掃描完成時(shí),觸發(fā)此事件
 /// 
 public event EventHandler> OnScanComplete;
 /// 
 /// 當(dāng)掃描進(jìn)度發(fā)生更改時(shí),觸發(fā)此事件
 /// 
 public event EventHandler OnScanProgressChanged;
 /// 
 /// 掃描端口
 /// 
 public int ScanPort { get; set; }
 /// 
 /// 單次請(qǐng)求的超時(shí)時(shí)長(zhǎng),默認(rèn)為2秒
 /// 
 public TimeSpan Timeout { get; set; }
 /// 
 /// 使用 TcpClient 測(cè)試是否可以連上指定的 IP 與 Port
 /// 
 /// 
 /// 
 /// 
 public bool IsConnected(IPAddress ipAddress, int port)
 {
  var result = TestConnection(ipAddress, port);
  return result.CanConnected;
 }
 /// 
 /// 使用 TcpClient 測(cè)試是否可以連上指定的 IP 與 Port
 /// 
 /// 
 /// 
 /// 
 public bool IsConnected(string ip, int port)
 {
  IPAddress ipAddress;
  if (IPAddress.TryParse(ip, out ipAddress))
  {
  return IsConnected(ipAddress, port);
  }
  else
  {
  throw new ArgumentException("IP 地址格式不正確");
  }
 }
 /// 
 /// 開(kāi)始掃描當(dāng)前網(wǎng)段
 /// 
 public void StartScan()
 {
  if (ScanPort == 0)
  {
  throw new InvalidOperationException("必須指定掃描的端口 ScanPort");
  }
  // 清除可能存在的數(shù)據(jù)
  _resultList.Clear();
  _totalCount = 0;
  _startTime = DateTimeOffset.Now;
  // 得到本網(wǎng)段的 IP
  var ipList = GetAllRemoteIPList();
  // 生成委托列表
  List> funcs = new List>();
  for (int i = 0; i < SegmentIpMaxCount; i++)
  {
  var tmpF = new Func(TestConnection);
  funcs.Add(tmpF);
  }
  // 異步調(diào)用每個(gè)委托
  for (int i = 0; i < SegmentIpMaxCount; i++)
  {
  funcs[i].BeginInvoke(ipList[i], ScanPort, OnComplete, funcs[i]);
  _totalCount += 1;
  }
 }
 /// 
 /// 得到本網(wǎng)段的所有 IP
 /// 
 /// 
 private List GetAllRemoteIPList()
 {
  var localName = Dns.GetHostName();
  var localIPEntry = Dns.GetHostEntry(localName);
  List ipList = new List();
  IPAddress localInterIP = localIPEntry.AddressList.FirstOrDefault(m => m.AddressFamily == AddressFamily.InterNetwork);
  if (localInterIP == null)
  {
  throw new InvalidOperationException("當(dāng)前計(jì)算機(jī)不存在內(nèi)網(wǎng) IP");
  }
  var localInterIPBytes = localInterIP.GetAddressBytes();
  for (int i = 1; i <= SegmentIpMaxCount; i++)
  {
  // 對(duì)末位進(jìn)行替換
  localInterIPBytes[3] = (byte)i;
  ipList.Add(new IPAddress(localInterIPBytes));
  }
  return ipList;
 }
 private void OnComplete(IAsyncResult ar)
 {
  var state = ar.AsyncState as Func;
  var result = state.EndInvoke(ar);
  lock (_locker)
  {
  // 添加到結(jié)果中
  _resultList.Add(result);
  // 報(bào)告進(jìn)度
  _totalCount -= 1;
  var percent = (SegmentIpMaxCount - _totalCount) * 100 / SegmentIpMaxCount;
  if (SynchronizationContext.Current == _originalContext)
  {
   OnScanProgressChanged?.Invoke(this, new ScanProgressEventArgs { Percent = percent });
  }
  else
  {
   _originalContext.Post(conState =>
   {
   OnScanProgressChanged?.Invoke(this, new ScanProgressEventArgs { Percent = percent });
   }, null);
  }
  if (_totalCount == 0)
  {
   // 通過(guò)事件拋出結(jié)果
   if (SynchronizationContext.Current == _originalContext)
   {
   OnScanComplete?.Invoke(this, _resultList);
   }
   else
   {
   _originalContext.Post(conState =>
   {
    OnScanComplete?.Invoke(this, _resultList);
   }, null);
   }
   // 計(jì)算耗時(shí)
   Debug.WriteLine("Compete");
   _endTime = DateTimeOffset.Now;
   Debug.WriteLine($"Duration: {_endTime - _startTime}");
  }
  }
 }
 /// 
 /// 測(cè)試是否可以連接到
 /// 
 /// 
 /// 
 /// 
 private ConnectionResult TestConnection(IPAddress address, int port)
 {
  TcpClient c = new TcpClient();
  ConnectionResult result = new ConnectionResult();
  result.Address = address;
  using (TcpClient tcp = new TcpClient())
  {
  IAsyncResult ar = tcp.BeginConnect(address, port, null, null);
  WaitHandle wh = ar.AsyncWaitHandle;
  try
  {
   if (!ar.AsyncWaitHandle.WaitOne(Timeout, false))
   {
   tcp.Close();
   }
   else
   {
   tcp.EndConnect(ar);
   result.CanConnected = true;
   }
  }
  catch
  {
  }
  finally
  {
   wh.Close();
  }
  }
  return result;
 }
 }
ServerScanner

以上代碼中注釋基本上已經(jīng)比較詳細(xì),這里再簡(jiǎn)單提幾個(gè)點(diǎn):

TestConnection 函數(shù)實(shí)了現(xiàn)核心功能,即請(qǐng)求給定的 IP 和端口,并返回結(jié)果;其中通過(guò)調(diào)用 IAsyncResult.AsyncWaitHandle 屬性的 WaitOne 方法來(lái)實(shí)現(xiàn)對(duì)超時(shí)的控制;

StartScan 方法中,在得到 IP 列表后,通過(guò)生成委托列表并異步調(diào)用這些委托來(lái)實(shí)現(xiàn)整個(gè)方法是異步的,不會(huì)阻塞 UI,而這些委托指向的方法就是 TestConnection 函數(shù);

使用同步上下文 SynchronizationContext,可以保證調(diào)用方在原來(lái)的線程(通常是 UI 線程)上處理進(jìn)度更新事件或掃描完成事件;

對(duì)于每個(gè)委托異步完成后,會(huì)執(zhí)行回調(diào)方法 OnComplete,在它里面,對(duì)全局變量的操作需要加鎖,以保證線程安全。

三、如何使用

最后來(lái)看一下如何使用,非常簡(jiǎn)單:

private void View_Loaded()
  {
   // 在界面 Load 事件中添加以下代碼
   ServerScanner.OnScanComplete += ServerScanner_OnScanComplete;
   ServerScanner.OnScanProgressChanged += ServerScanner_OnScanProgressChanged;
   // 掃描的端口號(hào)
   ServerScanner.ScanPort = 7890;
  }
  private void StartScan()
  {
   // 開(kāi)始掃描
   ServerScanner.StartScan();
  }

  private void ServerScanner_OnScanComplete(object sender, List e)
  {
   ...
  }
  private void ServerScanner_OnScanProgressChanged(object sender, ScanProgressEventArgs e)
  {
   ...
  }

以上是“.NET中如何實(shí)現(xiàn)掃描局域網(wǎng)服務(wù)”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對(duì)大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!


文章名稱:.NET中如何實(shí)現(xiàn)掃描局域網(wǎng)服務(wù)-創(chuàng)新互聯(lián)
網(wǎng)址分享:http://weahome.cn/article/dccces.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部