<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
        問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
        當前位置: 首頁 - 科技 - 知識百科 - 正文

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

        來源:懂視網 責編:小采 時間:2020-11-27 22:35:10
        文檔

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

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

        在最近負責的項目中,需要實現這樣一個需求:在客戶端程序中,掃描當前機器所在網段中的所有機器上是否有某服務啟動,并把所有已經啟動服務的機器列出來,供用戶選擇,連接哪個服務。注意:這里所說的服務事實上就是在一個固定的端口監聽基于 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中掃描局域網服務的實現方法就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

        聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

        文檔

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

        在.NET中掃描局域網服務的實現方法:在最近負責的項目中,需要實現這樣一個需求:在客戶端程序中,掃描當前機器所在網段中的所有機器上是否有某服務啟動,并把所有已經啟動服務的機器列出來,供用戶選擇,連接哪個服務。注意:這里所說的服務事實上就是在一個固定的端口監聽基于 TCP 協議的請求
        推薦度:
        標簽: 中的 方法 掃描
        • 熱門焦點

        最新推薦

        猜你喜歡

        熱門推薦

        專題
        Top
        主站蜘蛛池模板: 黄色免费网站网址| 99国产精品视频免费观看| 韩国二级毛片免费播放| 亚洲精品国产精品国自产网站| 日韩精品无码专区免费播放| 亚洲AV成人精品网站在线播放| 中文字幕无码一区二区免费| 亚洲AV无码专区电影在线观看| 女同免费毛片在线播放| 日韩亚洲AV无码一区二区不卡 | 91麻豆最新在线人成免费观看| 精品日韩亚洲AV无码一区二区三区| 最近免费中文字幕大全高清大全1| 久久精品国产亚洲av水果派| 国产成人福利免费视频| 亚洲日韩中文字幕一区| 国产免费看插插插视频| 国产精品偷伦视频免费观看了| 国产亚洲成AV人片在线观黄桃 | 91麻豆最新在线人成免费观看| 国产成人精品日本亚洲18图| 成人爱做日本视频免费| 亚洲免费日韩无码系列| 欧亚一级毛片免费看| 国产美女无遮挡免费视频| 亚洲国产一区二区三区在线观看| 国产男女猛烈无遮挡免费网站 | 边摸边吃奶边做爽免费视频网站| 亚洲综合区小说区激情区| 日韩精品久久久久久免费| 亚洲人成电影网站色| 在线亚洲97se亚洲综合在线| 57pao国产成永久免费视频| 亚洲欧美日韩中文无线码| 久久久久国产成人精品亚洲午夜 | 暖暖免费高清日本一区二区三区| 国产VA免费精品高清在线| 亚洲精品视频在线观看视频| 国产裸模视频免费区无码| 国偷自产一区二区免费视频| 美女视频黄免费亚洲|