亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > .NET > 正文

在.NET中掃描局域網服務的實現方法

2024-07-10 13:32:54
字體:
來源:轉載
供稿:網友

在最近負責的項目中,需要實現這樣一個需求:在客戶端程序中,掃描當前機器所在網段中的所有機器上是否有某服務啟動,并把所有已經啟動服務的機器列出來,供用戶選擇,連接哪個服務。注意:這里所說的服務事實上就是在一個固定的端口監聽基于 TCP 協議的請求的程序或者服務(如 WCF 服務)。

要實現這樣的功能,核心的一點就是在得到當前機器同網段的所有機器的 IP 后,對每一 IP 發生 TCP 連接請求,如果請求超時或者出現其它異常,則認為沒有服務,反之,如果能夠正常連接,則認為服務正常。

經過基本功能的實現以及后續的重構之后,就有了本文以下的代碼:一個接口和具體實現的類。需要說明的是:在下面的代碼中,先提到接口,再提到具體類;而在開發過程中,則是首先創建了類,然后才提取了接口。之所以要提取接口,原因有二:一是可以支持 IoC控制反轉;二是將來如果其它的同類需求,可以其于此接口實現新功能。

一、接口定義

先看來一下接口:

/// <summary> /// 掃描服務 /// </summary> public interface IServerScanner { /// <summary> /// 掃描完成 /// </summary> event EventHandler<List<ConnectionResult>> OnScanComplete; /// <summary> /// 報告掃描進度 /// </summary> event EventHandler<ScanProgressEventArgs> OnScanProgressChanged; /// <summary> /// 掃描端口 /// </summary> int ScanPort { get; set; } /// <summary> /// 單次連接超時時長 /// </summary> TimeSpan Timeout { get; set; } /// <summary> /// 返回指定的IP與端口是否能夠連接上 /// </summary> /// <param name="ipAddress"></param> /// <param name="port"></param> /// <returns></returns> bool IsConnected(IPAddress ipAddress, int port); /// <summary> /// 返回指定的IP與端口是否能夠連接上 /// </summary> /// <param name="ip"></param> /// <param name="port"></param> /// <returns></returns> bool IsConnected(string ip, int port); /// <summary> /// 開始掃描 /// </summary> void StartScan(); }

其中 Timeout 屬性是控制每次連接請求超時的時長。

二、具體實現

再來看一下具體實現類:

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

以上代碼中注釋基本上已經比較詳細,這里再簡單提幾個點:

TestConnection 函數實了現核心功能,即請求給定的 IP 和端口,并返回結果;其中通過調用 IAsyncResult.AsyncWaitHandle 屬性的 WaitOne 方法來實現對超時的控制;

StartScan 方法中,在得到 IP 列表后,通過生成委托列表并異步調用這些委托來實現整個方法是異步的,不會阻塞 UI,而這些委托指向的方法就是 TestConnection 函數;

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

對于每個委托異步完成后,會執行回調方法 OnComplete,在它里面,對全局變量的操作需要加鎖,以保證線程安全。

三、如何使用

最后來看一下如何使用,非常簡單:

private void View_Loaded()  {   // 在界面 Load 事件中添加以下代碼   ServerScanner.OnScanComplete += ServerScanner_OnScanComplete;   ServerScanner.OnScanProgressChanged += ServerScanner_OnScanProgressChanged;   // 掃描的端口號   ServerScanner.ScanPort = 7890;  }  private void StartScan()  {   // 開始掃描   ServerScanner.StartScan();  }  private void ServerScanner_OnScanComplete(object sender, List<ConnectionResult> e)  {   ...  }  private void ServerScanner_OnScanProgressChanged(object sender, ScanProgressEventArgs e)  {   ...  }

如果你有更好的建議或意見,請留言互相交流。

以上這篇在.NET中掃描局域網服務的實現方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到ASP.NET教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
久久久久国产一区二区三区| 亚洲自拍欧美色图| 久久精品免费电影| 欧美成年人视频网站欧美| 亚洲欧美在线免费观看| 亚洲小视频在线观看| 国产精品大片wwwwww| 亚洲国产精品专区久久| 亚洲综合日韩在线| 欧美精品在线观看| 国产精品av在线| 亚洲色图13p| 亚洲精品免费在线视频| 久久综合五月天| 色婷婷av一区二区三区在线观看| 日韩成人性视频| 亚洲xxxx在线| 日韩中文字幕网址| 国产成人+综合亚洲+天堂| 久久久久国产精品一区| 久久精品国产一区二区电影| 一区二区三欧美| 精品国产乱码久久久久久婷婷| 高清欧美性猛交xxxx黑人猛交| 一区二区日韩精品| 在线午夜精品自拍| 欧美激情视频在线观看| 91人人爽人人爽人人精88v| 91日韩在线播放| 狠狠干狠狠久久| 深夜福利国产精品| 92福利视频午夜1000合集在线观看| 国语自产精品视频在线看抢先版图片| 亚洲黄色片网站| 欧美成人精品在线播放| 97精品视频在线观看| 欧美激情精品久久久久久| 国产精品羞羞答答| 国产第一区电影| 日产精品久久久一区二区福利| 国产精品久久久久久久久久免费| 97久久精品国产| 欧美激情手机在线视频| 一区国产精品视频| 久久久久久久久久国产精品| 亚洲国产精品悠悠久久琪琪| 91在线观看免费网站| 亚洲成人免费网站| 亚洲精品一区二区三区婷婷月| 91精品国产网站| 欧美精品video| 国产成人综合精品| 成人a在线视频| 欧美在线视频a| 欧美亚洲成人xxx| 欧美国产日本高清在线| 国产精品麻豆va在线播放| 亚洲天堂av在线播放| 国产69久久精品成人看| 欧美日韩国产丝袜另类| 国产视频久久久久久久| 91精品久久久久久综合乱菊| 国产一区二区美女视频| 久久韩剧网电视剧| 欧美激情一区二区三级高清视频| 亚洲在线免费看| 高清一区二区三区四区五区| 福利精品视频在线| 国产精品欧美一区二区三区奶水| 日韩中文在线中文网三级| 国产日韩一区在线| 最近更新的2019中文字幕| 欧美片一区二区三区| 国产精品久久久久99| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲免费视频一区二区| 亚洲另类欧美自拍| 51视频国产精品一区二区| 久久久成人精品视频| 乱亲女秽乱长久久久| 久久成人这里只有精品| 国产经典一区二区| 日韩资源在线观看| 狠狠综合久久av一区二区小说| 中文字幕国产日韩| 午夜精品在线视频| 一夜七次郎国产精品亚洲| 欧美乱大交xxxxx| 91精品国产色综合久久不卡98口| 亚洲影院高清在线| 日韩中文在线中文网在线观看| 91影视免费在线观看| 国产精品久久久999| 亚洲片国产一区一级在线观看| 久久精品中文字幕电影| 成人性教育视频在线观看| 国产小视频国产精品| 欧美视频一区二区三区…| 国产91精品在线播放| 亚洲已满18点击进入在线看片| 91美女片黄在线观看游戏| 欧美肥老妇视频| 亚洲老司机av| 亚洲日本成人网| 久久久久久成人精品| 久久国产精品首页| 国产成人精品电影久久久| 91成人精品网站| 国产一区二区在线播放| 亚洲影视九九影院在线观看| 久久久精品美女| 成人a在线观看| 欧美性生交xxxxx久久久| 亚洲天堂免费在线| 91精品久久久久久久久久| 亚洲欧美国产一本综合首页| 中文字幕亚洲欧美日韩在线不卡| 欧美精品在线网站| 亚洲激情中文字幕| 韩日精品中文字幕| 日韩中文字幕网址| 久久99视频免费| 国产精品小说在线| 伊人青青综合网站| 国产亚洲视频中文字幕视频| 国产精品久久婷婷六月丁香| 尤物tv国产一区| 国产丝袜一区二区三区免费视频| www.亚洲一区| 亚洲va欧美va国产综合久久| 亚洲精品成人久久久| 日韩禁在线播放| 国产日产欧美精品| 日韩电影在线观看中文字幕| 亚洲精品国产电影| 国内精品伊人久久| 少妇高潮久久久久久潘金莲| 欧美一级视频免费在线观看| 久久久精品视频在线观看| 黑人精品xxx一区一二区| 一区二区欧美亚洲| 欧美精品www在线观看| 中文日韩在线观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 欧美精品久久久久| 国产美女久久久| 成人国产精品一区二区| 国产精品va在线播放| 97**国产露脸精品国产| 国产精品99一区| 性视频1819p久久| 国产精品精品国产| 国产精品亚洲视频在线观看| 国产欧美精品日韩| 91av国产在线| 亚洲一区二区三区视频播放| 国产精品久久久久久久久久东京| 91在线观看免费观看| 中文字幕免费精品一区| 亚洲成人999| 美女扒开尿口让男人操亚洲视频网站| 国产精品av免费在线观看| 奇米4444一区二区三区| 国产精品视频xxx|