C#用代碼控制網(wǎng)絡(luò)斷開與重連(c反應(yīng)蛋白高說明什么)

看到這個(gè)標(biāo)題,如果你想說誰會(huì)這么蛋疼,有網(wǎng)不好好上,那么說明你還是一個(gè)純潔的少年。自動(dòng)重?fù)艿男枨笏诙嘤?,主要是為了繞過各大網(wǎng)站對(duì)相同IP地址的重復(fù)請(qǐng)求次數(shù)限制等等。具體的我不說了,說多了說我教壞小孩子。我最近研究這個(gè)只是因?yàn)槲蚁雽憘€(gè)軟件自動(dòng)播放和下載某個(gè)網(wǎng)站的視頻,but這個(gè)網(wǎng)站一天只讓同個(gè)IP免費(fèi)看五個(gè)視頻,我又摳不愿意花錢,但是又特別想多看多載幾部。什么,你要我把網(wǎng)站地址告訴你?還是算了吧,傳播XX(se)OO(qing)是違法的知道不。

按慣例,先聲明:技術(shù)知識(shí)浩瀚無垠,筆者但求淺嘗輒止便心滿意足,所以,本文并不確保描述的準(zhǔn)確性,若有錯(cuò)誤和不足之處請(qǐng)不吝賜教。

上網(wǎng)方式簡(jiǎn)介


趁此機(jī)會(huì)簡(jiǎn)單了解下各類網(wǎng)絡(luò)接入方式。以下描述主要來自百度文檔《淺談各種寬帶上網(wǎng)的方法》,有興趣的朋友可以自行百度搜索文庫(kù)。

撥號(hào)上網(wǎng):20世紀(jì)90年代剛有互聯(lián)網(wǎng)的時(shí)候,老百姓上網(wǎng)使用最為普便的一種方式是撥號(hào)上網(wǎng)。只要用戶擁有一臺(tái)個(gè)人電腦、一個(gè)外置或內(nèi)置的調(diào)制解調(diào)器(modem)和一根電話線,再向本地ISP供應(yīng)商申請(qǐng)自己的賬號(hào),或購(gòu)買上網(wǎng)卡,擁有自己的用戶名和密碼后,然后通過撥打ISP的接入號(hào)連接到Internet上。那個(gè)時(shí)候,出差的人們常常會(huì)問賓館能否撥號(hào)上網(wǎng),然后問撥什么號(hào),之后以緩慢的速度發(fā)送郵件或“暢游”網(wǎng)絡(luò)。撥號(hào)方式理論上的最高速率56KBIT/S。除了速度慢外,同時(shí)只能進(jìn)行一項(xiàng)工作,比如上網(wǎng)了電話就打不進(jìn)來。

ISDN:準(zhǔn)確地說應(yīng)是N-ISDN,即窄帶ISDN,它主要提供64kbit/s到2Mbit/s的接入能力、目前推向用戶的ISDN業(yè)務(wù)是基本速率接口,即2B D,每個(gè)B通道為64kbit/s,D通道為16kbit/s,ISDN在Internet接入方面比普通用戶以56kbit/s的Modem上網(wǎng)具有無可比擬的優(yōu)勢(shì)。首先,由于ISDN提供了2B+D的功能,使得用戶可以一面以64kbit/s的速度上網(wǎng),一面又可以同時(shí)使用另一通道打電話而互不干擾,非常方便;其次,ISDN是數(shù)字式設(shè)備,因而接入速度相當(dāng)快,不像Modem那樣要有很長(zhǎng)的建立時(shí)間,全數(shù)字的網(wǎng)絡(luò)使建立只需幾秒鐘;最后,由于ISDN提供2B D方式,使得用戶可以綁定兩個(gè)B通道上網(wǎng),最高速率可達(dá)128kbit/s,比56k Modem的接入速率快2.2倍,真正可以做到網(wǎng)上沖浪。

ADSL:近幾年最普遍的網(wǎng)絡(luò)接入方式。長(zhǎng)期以來通信用戶的電話機(jī)經(jīng)過”對(duì)絞銅線”的用戶線連至市內(nèi)交換局,進(jìn)入公共交換的通信網(wǎng)(PSTN),接至對(duì)方用戶的電話機(jī),使雙方得以互相會(huì)話。對(duì)絞銅線為傳統(tǒng)的模擬電話提供300~3400Hz 的頻帶,為了適應(yīng)電話用戶使用低速數(shù)據(jù)通信,曾加裝調(diào)制一解調(diào)器(modem),使速率33kb/s 和最高56kb/s 的數(shù)據(jù)信號(hào)能夠通過模擬話音頻帶與對(duì)方實(shí)行數(shù)據(jù)通信。這就是撥號(hào)上網(wǎng)方式的基礎(chǔ)。話音modem 只能提供56kb/s 的數(shù)據(jù)速率。為什么對(duì)絞銅線只能傳輸以56kb/s 為限度的數(shù)據(jù)呢?應(yīng)該說,這不是對(duì)絞銅線傳輸能力的限度,而是通信網(wǎng)中的交換機(jī)有限制,它對(duì)電話通信只是分配一個(gè)話音頻帶。雖然用戶的數(shù)據(jù)信息經(jīng)過話音modem,交換機(jī)并不認(rèn)出它是話音modem 傳來的數(shù)據(jù)信號(hào),而只是對(duì)它當(dāng)作話音信號(hào)看待。對(duì)絞銅線本身并不限制定帶數(shù)據(jù)信號(hào)的傳輸,只要避開窄帶交換機(jī),用戶就可以把寬帶數(shù)據(jù)信號(hào)送進(jìn)通信網(wǎng)。因此我們說,用戶線如避開了窄帶的話音交換機(jī),就可成為”數(shù)字用戶線”(DSL,Digital Subscriber Line)。簡(jiǎn)單地說,ADSL可以利用現(xiàn)有的電話線網(wǎng)絡(luò),只要在線路兩端加裝ADSL設(shè)備,即可為用戶提供高寬帶服務(wù),提供8MBIT/S的高速下行速率,遠(yuǎn)高于ISDN速率,而上行速率有1MBIT/S,是普通電話拔號(hào)MODEM的百倍以上,傳輸距離能達(dá)3-5KM。當(dāng)然ADSL的商業(yè)化推進(jìn)也經(jīng)過了各方面多年的努力。有人會(huì)問,“我家用的就是ADSL,怎么每次還要彈出一個(gè)撥號(hào)界面讓我輸入賬號(hào)密碼呢?”實(shí)際上,ADSL本身是不需要撥號(hào)的,而是一種專線鏈接。撥號(hào)的目的僅僅是認(rèn)證用戶的身份并進(jìn)行計(jì)費(fèi),因此叫做虛擬撥號(hào)。虛擬撥號(hào)需要用到虛擬撥號(hào)軟件,常用的有WinPoET ,虛擬撥號(hào)軟件在安裝過程中會(huì)提示將撥號(hào)綁定到與ADSL Modem 相連的網(wǎng)卡。配置好以后,撥號(hào)形式與56Kbps模擬Modem完全一樣,在對(duì)話框里輸入ISP提供的用戶名和密碼就可以了。ADSL還涉及到PPPOE的概念,有空再研究吧。

光纖入戶:很明顯,最直觀的區(qū)別就是傳輸介質(zhì)不同,當(dāng)然相關(guān)的接入技術(shù)肯定也是不同的,網(wǎng)速比ADSL又有了很大提升,就不贅述了。筆者安裝光纖時(shí),電信也給了一個(gè)類似Modem的東西,工作人員也把它叫做“貓”,其實(shí)和撥號(hào)方式用的Modem不是同個(gè)東西,但是本質(zhì)還是主要用來處理信號(hào)轉(zhuǎn)換。

ISDN沒接觸過就不說了,傳統(tǒng)撥號(hào)和ADSL都可以通過調(diào)用撥號(hào)程序控制網(wǎng)絡(luò)的斷開與連接,如果ADSL入戶時(shí)接入到路由器上,那么可以通過重啟路由器的方式進(jìn)行IP更換。光纖入戶時(shí)常也接路由器(光貓?jiān)咀詭o線路由功能,但是有時(shí)電信會(huì)把這個(gè)功能給鎖掉讓你用不了,很坑爹),但是賬號(hào)和密碼是保存在光貓里的,所以要重啟的是光貓(似乎也有方法可以通過路由器進(jìn)行撥號(hào),筆者沒研究過)。重啟路由器和光貓很簡(jiǎn)單,調(diào)用設(shè)備管理頁面的重啟請(qǐng)求即可。下面我們主要講如何通過自動(dòng)撥號(hào)進(jìn)行網(wǎng)絡(luò)重連。

RAS概述


現(xiàn)如今,社會(huì)已經(jīng)離不了網(wǎng)絡(luò),企事業(yè)單位對(duì)網(wǎng)絡(luò)的需求也在不斷擴(kuò)大,各地分支機(jī)構(gòu)都需要與總部隨時(shí)進(jìn)行信息交換。雖然通過Intemet能很好實(shí)現(xiàn)遠(yuǎn)程數(shù)據(jù)的傳輸,但需要總部與各地分支機(jī)構(gòu)都擁有良好的上網(wǎng)條件和IP地址。在實(shí)際工作中,出于成本上的考慮,大多數(shù)中小型企業(yè)多采用傳統(tǒng)的通過調(diào)制解調(diào)器和電話線直接撥號(hào)的方式來實(shí)現(xiàn)遠(yuǎn)程數(shù)據(jù)的傳輸(并不一定經(jīng)由Internet,更類似于局域網(wǎng))。

遠(yuǎn)程訪問服務(wù)(Remote Access seryice)利用公共交換電話網(wǎng)絡(luò)(PSTN)把遠(yuǎn)離局域網(wǎng)(LAN)的計(jì)算機(jī)連接到局域網(wǎng)上來,遠(yuǎn)程計(jì)算機(jī)(RAS客戶機(jī))可以獲得LAN用戶的所有服務(wù)和權(quán)限,并訪問、共享該LAN上的資源。它所實(shí)施的網(wǎng)絡(luò)互聯(lián)架構(gòu),在提供網(wǎng)絡(luò)互聯(lián)的同時(shí),可以集中發(fā)布各種應(yīng)用程序,包括Web應(yīng)用程序,以及幾乎所有部署在臺(tái)式機(jī)的應(yīng)用程序。分析結(jié)果顯示,維持RAS正常使用所需要的帶寬相當(dāng)?shù)停脩舳颂峁┳畹?8Kbps快速訪問。相對(duì)于傳統(tǒng)的組網(wǎng)方案, RAS提供了更為快速、安全、靈活和可管理的遠(yuǎn)程應(yīng)用接入方案,使人們可以隨需應(yīng)變,通過任何網(wǎng)絡(luò)連接方式對(duì)企業(yè)進(jìn)行隨時(shí)隨地的安全訪問,為企業(yè)的 ERP 、 CRM 、 OA 等信息應(yīng)用系統(tǒng)全面提速。RAS適用于行業(yè)用戶使用,如:企業(yè)辦公網(wǎng)絡(luò),政府辦公網(wǎng)絡(luò)、稅收征收系統(tǒng)、電力系統(tǒng)、醫(yī)療領(lǐng)域等等。

遠(yuǎn)程訪問服務(wù)支持撥號(hào)網(wǎng)絡(luò)(DUN)連接與虛擬專用網(wǎng)絡(luò)(VPN)連接兩種不同的遠(yuǎn)程訪問連接方式。撥號(hào)網(wǎng)絡(luò)(DUN)連接就是遠(yuǎn)程客戶機(jī)利用一個(gè)連接了電話線的調(diào)制解調(diào)器,通過撥號(hào)的方式呼叫遠(yuǎn)程計(jì)算機(jī)并建立連接。虛擬專用網(wǎng)絡(luò)(VPN)是遠(yuǎn)程客戶機(jī)使用基于TCP/IP協(xié)議的專門隧道協(xié)議(如PPTP、L2TP),通過虛擬專用網(wǎng)絡(luò)服務(wù)器的虛擬端口,借助其他網(wǎng)絡(luò)(如Intemet),實(shí)現(xiàn)一種邏輯上的直接連接。

VPN屬于遠(yuǎn)程訪問技術(shù),簡(jiǎn)單地說就是利用公用網(wǎng)絡(luò)架設(shè)專用網(wǎng)絡(luò)。例如某公司員工出差到外地,他想訪問企業(yè)內(nèi)網(wǎng)的服務(wù)器資源,這種訪問就屬于遠(yuǎn)程訪問。在傳統(tǒng)的企業(yè)網(wǎng)絡(luò)配置中,要進(jìn)行遠(yuǎn)程訪問,傳統(tǒng)的方法是租用DDN(數(shù)字?jǐn)?shù)據(jù)網(wǎng))專線或幀中繼,這樣的通訊方案必然導(dǎo)致高昂的網(wǎng)絡(luò)通訊和維護(hù)費(fèi)用。對(duì)于移動(dòng)用戶(移動(dòng)辦公人員)與遠(yuǎn)端個(gè)人用戶而言,一般會(huì)通過撥號(hào)線路(Internet)進(jìn)入企業(yè)的局域網(wǎng),但這樣必然帶來安全上的隱患。

讓外地員工訪問到內(nèi)網(wǎng)資源,利用VPN的解決方法就是在內(nèi)網(wǎng)中架設(shè)一臺(tái)VPN服務(wù)器。外地員工在當(dāng)?shù)剡B上互聯(lián)網(wǎng)后,通過互聯(lián)網(wǎng)連接VPN服務(wù)器,然后通過VPN服務(wù)器進(jìn)入企業(yè)內(nèi)網(wǎng)。為了保證數(shù)據(jù)安全,VPN服務(wù)器和客戶機(jī)之間的通訊數(shù)據(jù)都進(jìn)行了加密處理。有了數(shù)據(jù)加密,就可以認(rèn)為數(shù)據(jù)是在一條專用的數(shù)據(jù)鏈路上進(jìn)行安全傳輸,就如同專門架設(shè)了一個(gè)專用網(wǎng)絡(luò)一樣,但實(shí)際上VPN使用的是互聯(lián)網(wǎng)上的公用鏈路,因此VPN稱為虛擬專用網(wǎng)絡(luò),其實(shí)質(zhì)上就是利用加密技術(shù)在公網(wǎng)上封裝出一個(gè)數(shù)據(jù)通訊隧道。有了VPN技術(shù),用戶無論是在外地出差還是在家中辦公,只要能上互聯(lián)網(wǎng)就能利用VPN訪問內(nèi)網(wǎng)資源,這就是VPN在企業(yè)中應(yīng)用得如此廣泛的原因。

P/Invoke


我們可以借助RASapi實(shí)現(xiàn)軟件的自動(dòng)撥號(hào)。RAS APl最早是在windows for workgroup 3.11中出現(xiàn)的,現(xiàn)已成為win32 API的一個(gè)組成部分。RAS API提供了專門用于實(shí)現(xiàn)RAS功能的函數(shù),根據(jù)其具體的功能分別存放在API32.DLL、RASDLG.DLL和RASSAPI.DLL三個(gè)動(dòng)態(tài)鏈接庫(kù)中。其中,RASAPl32.DLL封裝了RAS客戶功能的函數(shù),RASDLG.DLL封裝了幾個(gè)基于對(duì)話框的功能函數(shù),RASSAPI.DLL則封裝了RAS Server的一些管理函數(shù)。

RAS API將整個(gè)撥號(hào)網(wǎng)絡(luò)視為RAS電話簿(Phonebook),而每一個(gè)連接視為電話簿條目(PhonebookEntry)。調(diào)用RasCreatePhonebookEntry創(chuàng)建新的連接,調(diào)用RasDial進(jìn)行撥號(hào),調(diào)用RasEnumEntries獲得當(dāng)前系統(tǒng)已有的所有連接,調(diào)用其它的RAS函數(shù)還可以分別實(shí)現(xiàn)獲取或設(shè)置連接參數(shù)等功能。

作為.NETer,偶爾要借助P/Invoke調(diào)用Win32Api,以RASAPI中的核心函數(shù)RasDial為例,看用C#如何封裝對(duì)該函數(shù)的調(diào)用。

還有個(gè)api名曰InternetDial,也能用來寫撥號(hào)程序,就不知道它和RasApi的區(qū)別有哪些。MSDN里說道InternetDial does not support double-dial connections, SmartCard authentication, or connections that require registry-based certification. Starting on Windows Vista and Windows Server 2008, the WinINet dial-up functions use the RAS functions to establish a dial-up connection. WinINet supports the functionality documented in the RasDialDlg function. 所以我想現(xiàn)在還是用RAS比較靠譜一點(diǎn)。

首先在MSDN中查看RasDial的定義如下:

DWORD RasDial( _In_ LPRASDIALEXTENSIONS lpRasDialExtensions, _In_ LPCTSTR lpszPhonebook, _In_ LPRASDIALPARAMS lpRasDialParams, _In_ DWORD dwNotifierType, _In_ LPVOID lpvNotifier, _Out_ LPHRASCONN lphRasConn);

然后我們要將Win32類型轉(zhuǎn)為C#類型。由于 DWORD 是 4 字節(jié)的整數(shù),因此我們可以使用 int 或 uint 作為 C# 對(duì)應(yīng)類型。由于 int 是 CLS 兼容類型(可以用于所有 .NET 語言),以此比 uint 更常用,并且在多數(shù)情況下,它們之間的區(qū)別并不重要。以P或LP開頭的類型一般都是指針,對(duì)應(yīng)的C#類型需要為引用類型,如果作為參數(shù)使用,那么也可以使用值類型,前面加上ref/out關(guān)鍵字即可;還有一種方法,就是使用CLR中的System.IntPrt作為萬能指針去對(duì)應(yīng)任意Win32指針類型,它沒有要求一開始就定義對(duì)應(yīng)的數(shù)據(jù)類型,后面用到時(shí)再賦予即可(概念上有點(diǎn)類似于Object)。不像系統(tǒng)中的其他基類型,IntPtr 并沒有固定的大小。相反,它在運(yùn)行時(shí)的大小是依底層操作系統(tǒng)的正常指針大小而定的。這意味著在 32 位的 Windows 中,IntPtr 變量的寬度是 32 位的,而在 64 位的 Windows 中,實(shí)時(shí)編譯器編譯的代碼會(huì)將 IntPtr 值看作 64 位的值。當(dāng)在托管代碼和非托管代碼之間封送不透明指針時(shí),這種自動(dòng)調(diào)節(jié)大小的特點(diǎn)十分有用。

我們平時(shí)常說的32位、64位系統(tǒng),這里的位數(shù)其實(shí)指的是最大尋址空間,即內(nèi)存的最大大小,也就是說使用32位操作系統(tǒng)支持的內(nèi)存也最多為2的32次方,就是4G。和數(shù)據(jù)類型占用的字節(jié)大小沒有關(guān)系。

RASDIALEXTENSIONS是指向一個(gè)結(jié)構(gòu)的指針,定義如下:

typedef struct _RADIALEXTENSIONS { DWORD dwSize; DWORD dwfOptions; HWND hwndParent; ULONG_PTR reserved; ULONG_PTR reserved1; RASEAPINFO RasEapInfo; BOOL fSkipPppAuth; RASDEVSPECIFICINFO RasDevSpecificInfo;} RASDIALEXTENSIONS, *PRASDIALEXTENSIONS;

根據(jù)上述,在c#中我們可以使用class替代它,由于這個(gè)結(jié)構(gòu)是作為RasDial函數(shù)的一個(gè)參數(shù)傳遞,因此我們也可以使用struct替代,并在調(diào)用方法的時(shí)候在此參數(shù)前加上ref/out(若將參數(shù)作為一個(gè)整體操作,那么class也必須加上ref/out,避免出現(xiàn)實(shí)參/形參引用不一致的情況),當(dāng)然,在方法調(diào)用的時(shí)候,我們也可以使用System.IntPrt指向之,略微麻煩一點(diǎn)的是,IntPrt需要手動(dòng)為其分配非托管內(nèi)存并寫入數(shù)據(jù),所幸借助System.Runtime.InteropServices.Marshal類的相關(guān)方法,這部分工作也很簡(jiǎn)單。

c#表示如下(RASDIALEXTENSIONS最后兩個(gè)字段是Win7之后新增的,在編碼的時(shí)候要注意):

[StructLayout(LayoutKind.Sequential, Pack = 4)] public struct RASDIALEXTENSIONS { public int size; public RDEOPT options; public IntPtr handle; public IntPtr reserved; public IntPtr reserved1; public RASEAPINFO eapInfo;#if (WIN7 || WIN8) public bool skipPppAuth; public RASDEVSPECIFICINFO devSpecificInfo;#endif }

WIN7、WIN8是在VS里自定義的條件編譯符號(hào),略過不談。StructLayout特性指示結(jié)構(gòu)字段在內(nèi)存中如何分布,當(dāng)導(dǎo)出到非托管代碼時(shí)非托管對(duì)象亦按此布局。StructLayout有四個(gè)屬性:

  1. LayoutKind,有三個(gè)枚舉值:Sequential,對(duì)象的成員按照它們出現(xiàn)的順序依次布局,并且同StructLayout的另一個(gè)屬性Pack有關(guān),詳細(xì)規(guī)則可以參考百度的一篇文章<<內(nèi)存對(duì)齊的規(guī)則以及作用>>,那篇文章中的#pragma pack()同這里的Pack作用一樣;Explicit,對(duì)象的各個(gè)成員的精確位置被顯式控制,每個(gè)成員必須使用 System.Runtime.InteropServices.FieldOffsetAttribute指示該字段在類型中的位置,當(dāng)映射到C/C 的union時(shí),該枚舉值非常有用;Auto,運(yùn)行時(shí)自動(dòng)對(duì)象的成員選擇適當(dāng)?shù)牟季?,可能?huì)對(duì)字段順序進(jìn)行調(diào)整,使實(shí)例占用盡可能少的內(nèi)存(當(dāng)然前提是各個(gè)字段獨(dú)享自己的內(nèi)存,不同于union)??紤]到CPU讀取效率,一般采用LayoutKind.Sequential。
  2. Pack,第1條已述。
  3. CharSet,指示字符是單字節(jié)or雙字節(jié),這主要是歷史遺留問題??梢詫⒅O(shè)為Auto,這樣,在 Windows NT、Windows 2000、Windows XP 和 Windows Server2003 系列上,默認(rèn)值為 System.Runtime.InteropServices.CharSet.Unicode;在 Windows 98 和 Windows Me 上,默認(rèn)值為 System.Runtime.InteropServices.CharSet.Ansi。
  4. Size,指示類或結(jié)構(gòu)的絕對(duì)大小。不常用,但是如果需要在結(jié)構(gòu)末尾分配額外的空間,則可能會(huì)用到此屬性。

結(jié)構(gòu)體的ULONG_PTR等表示基元類型指針的字段,只能使用IntPtr映射;若字段有預(yù)定義的若干值表示有意義的狀態(tài)指示等,則可以使用enum映射,如dwfOptions標(biāo)記RasDial的某些擴(kuò)展信息,這些標(biāo)記可以用枚舉值表示。

[Flags] public enum RDEOPT { None = 0x0, UsePrefixSuffix = 0x1, PausedStates = 0x2, IgnoreModemSpeaker = 0x4, //… }

RasDial還有個(gè)參數(shù)值得注意——lpvNotifier——雖然LPVOID類型表示這是個(gè)不透明指針,用IntPtr即可,但文檔所述表明這是個(gè)回調(diào)函數(shù)參數(shù),當(dāng) Win32 函數(shù)需要返回多項(xiàng)數(shù)據(jù)時(shí),通常都是通過回調(diào)機(jī)制來實(shí)現(xiàn)的,開發(fā)人員將函數(shù)指針傳遞給函數(shù)。.Net中有個(gè)類型專門作為方法的引用——Delegate,所以用Delegate映射更精確更方便。

最終RasDial函數(shù)的C#封裝版本如下:

[DllImport(NativeMethods.RasApi32Dll, CharSet = CharSet.Unicode)] private static extern int RasDial( IntPtr lpRasDialExtensions, string lpszPhonebook, IntPtr lpRasDialParams, RasNotifierType dwNotifierType, Delegate lpvNotifier, out RasHandle lphRasConn);

可以看到lpRasDialExtensions使用的類型是IntPtr,如前所述,我們要手動(dòng)為其分配內(nèi)存(非托管),并寫入相應(yīng)數(shù)據(jù),關(guān)鍵代碼如下:

try { IntPtr lpRasDialExtensions = IntPtr.Zero; var extensions = new RASDIALEXTENSIONS(); //根據(jù)StructLayout相關(guān)屬性計(jì)算內(nèi)存大小 int extensionsSize = Marshal.SizeOf(typeof(RASDIALEXTENSIONS)); extensions.size = extensionsSize;#if (WIN7 || WIN8) extensions.devSpecificInfo.size = Marshal.SizeOf(typeof(RASDEVSPECIFICINFO));#endif lpRasDialExtensions = Marshal.AllocHGlobal(extensionsSize); Marshal.StructureToPtr(extensions, lpRasDialExtensions, true); } catch (Exception) { //… } finally { if (lpRasDialExtensions != IntPtr.Zero) { Marshal.FreeHGlobal(lpRasDialExtensions); } }

代碼并不復(fù)雜,其中Marshal.StructureToPtr(object structure, IntPtr ptr, bool fDeleteOld)方法的第三個(gè)參數(shù)說明如下:

假設(shè) ptr 指向非托管內(nèi)存塊。此內(nèi)存塊的布局由相應(yīng)的托管類 structure 描述。StructureToPtr將字段值從結(jié)構(gòu)封送到指針。假設(shè) ptr 塊包含引用字段,該字段指向當(dāng)前包含“abc”的字符串緩沖區(qū)。假設(shè)托管端上相應(yīng)的字段是包含“vwxyz”的字符串。如果不另行通知它,StructureToPtr將分配一個(gè)新的非托管緩沖區(qū)來保存“vwxyz”,并將它掛鉤到ptr 塊。這將丟棄舊緩沖區(qū)“abc”使之漂移而不將其釋放回非托管堆。最后,您將得到一個(gè)孤立的緩沖區(qū),它表示在代碼中存在內(nèi)存泄漏。如果將 fDeleteOld 參數(shù)設(shè)置為真,則StructureToPtr 在繼續(xù)為“vwxyz”分配新緩沖區(qū)之前釋放保存“abc”的緩沖區(qū)。

調(diào)用結(jié)束后記住要使用Marshal.FreeHGlobal釋放非托管內(nèi)存。

DotRas


以上代碼來自于一個(gè)開源項(xiàng)目DotRas,雖然我并不提倡重復(fù)造輪子,但大概知道輪子怎么造總沒有壞處。由于筆者家里條件不允許——光纖入戶——so,我借用朋友的虛擬機(jī)(ADSL)進(jìn)行DotRas的調(diào)用測(cè)試,主要代碼如下:

//斷開private void btnHangUp_Click(object sender, RoutedEventArgs e){ if (_dataContext.SelectedRasConnection != null) { var conns = RasConnection.GetActiveConnections();//獲取當(dāng)前所有活動(dòng)連接 var conn = conns.First(o => o.EntryId == _dataContext.SelectedRasConnection.EntryId); if (conn != null) { RasIPInfo ipAddresses = (RasIPInfo)conn.GetProjectionInfo(RasProjectionType.IP); tbTestInfo.Text = “_前_” ipAddresses.IPAddress.ToString(); conn.HangUp();//斷開,斷開后RasConnection.GetActiveConnections()返回值里就沒它了 System.Threading.Thread.Sleep(10000); DialUp(_dataContext.SelectedRasConnection.EntryName); } }}//撥號(hào)連接private void DialUp(string entryname){ RasDialer dialer = new RasDialer(); dialer.EntryName = entryname; dialer.PhoneNumber = ” “; dialer.AllowUseStoredCredentials = true; dialer.PhoneBookPath = RasPhoneBook.GetPhoneBookPath(RasPhoneBookType.AllUsers); dialer.Timeout = 1000; dialer.Dial(); if (_dataContext.SelectedRasConnection != null) { var conns = RasConnection.GetActiveConnections(); var conn = conns.First(o => o.EntryId == _dataContext.SelectedRasConnection.EntryId); if (conn != null) { RasIPInfo ipAddresses = (RasIPInfo)conn.GetProjectionInfo(RasProjectionType.IP); tbTestInfo.Text = “_后_” ipAddresses.IPAddress.ToString(); } }}

界面如圖:

C#用代碼控制網(wǎng)絡(luò)斷開與重連(c反應(yīng)蛋白高說明什么)

點(diǎn)斷開后,果然遠(yuǎn)程桌面斷開了:

C#用代碼控制網(wǎng)絡(luò)斷開與重連(c反應(yīng)蛋白高說明什么)

10秒鐘后,虛擬機(jī)重?fù)苓B接,再等待一段時(shí)間后(這個(gè)時(shí)間比較長(zhǎng)有1到3分鐘,遠(yuǎn)遠(yuǎn)沒達(dá)到實(shí)用的標(biāo)準(zhǔn),可能是花生殼域名重新解析的緣故;經(jīng)朋友在本地測(cè)試,速度杠杠的),界面重新展現(xiàn):

C#用代碼控制網(wǎng)絡(luò)斷開與重連(c反應(yīng)蛋白高說明什么)

可以看到前后的IP是不一樣的。

相關(guān)新聞

聯(lián)系我們
聯(lián)系我們
公眾號(hào)
公眾號(hào)
在線咨詢
分享本頁
返回頂部