国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發(fā)設(shè)計 > 正文

VC編程輕松獲取局域網(wǎng)連接通知

2019-11-17 05:02:27
字體:
供稿:網(wǎng)友
一、 問題提出的背景

  筆者所使用的局域網(wǎng)擁有一個服務(wù)器及若干分布于各辦公室的客戶機,通過網(wǎng)卡相連。服務(wù)器不提供專線上網(wǎng),但可以撥號上網(wǎng),而各客戶機可以通過裝在服務(wù)器端的代理服務(wù)器共用一條電話線上網(wǎng),但前提必須是服務(wù)器已經(jīng)撥號連接。考慮到經(jīng)濟原因,服務(wù)器不可能長時間連在網(wǎng)上,因此經(jīng)常出現(xiàn)由于分布于各辦公室的客戶機不能知道服務(wù)器是否處于連線狀態(tài)而造成的想上網(wǎng)時服務(wù)器沒有撥號,或是服務(wù)器已經(jīng)撥號而客戶機卻并不知曉的情況,這無疑會在工作中帶來極大的不便。而筆者作為一名程序設(shè)計人員,有必要利用自己的專業(yè)優(yōu)勢來解決實際工作中所碰到的一些問題。通過對實際情況的分析,可以歸納為一點:當服務(wù)器在進行撥號連接時能及時通知在網(wǎng)絡(luò)上的各個客戶機,而各客戶機在收到服務(wù)器發(fā)來的消息后可以根據(jù)自己的情況來決定是否上網(wǎng)。這樣就可以在同一時間內(nèi)同時為較多的客戶機提供上網(wǎng)服務(wù),此舉不僅提高了利用效率也大大節(jié)省了上網(wǎng)話費。

  二、 程序主要設(shè)計思路及實現(xiàn)

  由于本網(wǎng)絡(luò)是通過網(wǎng)卡連接的局域網(wǎng),因此可以首選Windows Socket API進行套接字編程。整個系統(tǒng)分為兩部分:服務(wù)端和客戶端。服務(wù)端運行于服務(wù)器上負責監(jiān)視服務(wù)器是否在進行撥號連接,一旦發(fā)現(xiàn)馬上通過網(wǎng)絡(luò)發(fā)送消息通知客戶端;而客戶端軟件則只需完成同服務(wù)端軟件的連接并能接收到從服務(wù)端發(fā)送來的通知消息即可。服務(wù)器端要完成比客戶端更為繁重的任務(wù)。下面對這幾部分的實現(xiàn)分別加以描述:

  (一)監(jiān)視撥號連接事件的發(fā)生

  在采用撥號上網(wǎng)時,首先需要通過撥號連接通過電話線連接到ISP上,然后才能享受到ISP所提供的各種互聯(lián)網(wǎng)服務(wù)。而要捕捉撥號連接發(fā)生的事件不能依靠于消息通知,因為此時發(fā)出的消息同一個對話框出現(xiàn)在屏幕上時所產(chǎn)生的消息是一樣的。唯一同其他對話框區(qū)別的是其標題是固定的"撥號連接",因此在無其他非凡情況下(如其他程序的標題也是"撥號連接"時)可以認定當桌面上的所有程序窗口出現(xiàn)以"撥號連接" 為標題的窗口時,即可認定此時正在進行撥號連接。因此可以通過搜尋并判定窗口標題的辦法對撥號連接進行監(jiān)視,具體可以用CWnd類的FindWindows()函數(shù)來實現(xiàn):

CWnd *pWnd=CWnd::FindWindow(NULL,"撥號連接");
  第一個參數(shù)為NULL,指定對當前所有窗口都進行搜索。第二個參數(shù)就是待搜尋的窗口標題,一旦找到將返回該窗口的窗口句柄。因此可以在窗口句柄不為空的情況下去通知客戶端服務(wù)器現(xiàn)在正在撥號。由于一般的撥號連接都需要一段時間的連接應(yīng)答后才能登錄到ISP上,因此從提高程序運行效率角度出發(fā)可以通過定時器的使用來每間隔一段時間(如500毫秒)去搜尋一次,以確保能監(jiān)視到每一次的撥號連接而又不致過分加重CPU的負擔。 QQread.com 推出Windows2003教程 win2003安裝介紹 win2003網(wǎng)絡(luò)優(yōu)化 win2003使用技巧 win2003系統(tǒng)故障 服務(wù)器配置 專家答疑 更多的請看:http://www.qqread.com/windows/2003/index.Html  (二)服務(wù)器端網(wǎng)絡(luò)通訊功能的實現(xiàn)

  在此采用的是可靠的有連接的流式套接字,并且采用了多線程和異步通知機制能有效避免一些函數(shù)如accept()等的阻塞會引起整個程序的阻塞。由于套接字編程方面的書籍資料非常豐富,對其進行網(wǎng)絡(luò)編程做了很具體的描述,故本文在此只針對一些要害部分做簡要說明,有關(guān)套接字網(wǎng)絡(luò)編程的具體內(nèi)容請參閱相關(guān)資料。采用流式套接字的服務(wù)器端的主要設(shè)計流程可以歸結(jié)為以下幾步:

  1. 創(chuàng)建套接字

sock=socket(AF_INET,SOCK_STREAM,0);
  該函數(shù)的第一個參數(shù)用于指定地址族,在Windows下僅支持AF_INET(TCP/ip地址);第二個參數(shù)用于描述套接字的類型,對于流式套接字提供有SOCK_STREAM;最后一個參數(shù)指定套接字使用的協(xié)議,一般為0。該函數(shù)的返回值保存了新套接字的句柄,在程序退出前可以用closesocket()函數(shù)來將其釋放。

  2. 綁定套接字

  服務(wù)器方一旦獲取了一個新的套接字后應(yīng)通過bind()將該套接字與本機上的一個端口相關(guān)聯(lián)。此時需要預(yù)先對一個指向包含有本機IP地址和端口信息的sockaddr_in結(jié)構(gòu)填充一些必要的信息,如本地端口號和本地主機地址等。然后就可經(jīng)過bind()將服務(wù)器進程在網(wǎng)絡(luò)上標識出來。需要注重的是由于1024以內(nèi)的埠號都是保留的端口號因此如無非凡需要一般不能將sockin.sin_port的端口號設(shè)置為1024以內(nèi)的值:

……
sockin.sin_family=AF_INET;
sockin.sin_addr.s_addr=0;
sockin.sin_port=htons(USERPORT);
bind(sock,(LPSOCKADDR)&sockin,sizeof(sockin));
……
  3. 偵聽套接字

listen(sock,1);
  4. 等待客戶機的連接

  這里需要通過accept()調(diào)用等待接收客戶端的連接以完成連接的建立,由于該函數(shù)在沒有客戶端進行申請連接之前會處于阻塞狀態(tài),因此假如采取通常的單線程模式會導致整個程序一直處于阻塞狀態(tài)而不能響應(yīng)其他的外界消息,因此為該部分代碼單獨開辟一個線程,這樣阻塞將被限制在該線程內(nèi)而不會影響到程序整體。

AfxBeginThread(Server,NULL);//創(chuàng)建一個新的線程
……
UINT Server(LPVOID lpVoid)//線程的處理函數(shù)
{
//獲取當前視類的指針,以確保訪問的是當前的實例對象。
CNetServerView* pView=((CNetServerView*)(
(CFrameWnd*)AfxGetApp()->m_pMainWnd)->GetActiveView());
while(pView->nNumConns<1)//當前的連接者個數(shù)
{
int nLen=sizeof(SOCKADDR);
pView->newskt= accept(pView->sock,
(LPSOCKADDR)& pView->sockin,(LPINT)& nLen);
WSAAsyncSelect(pView->newskt,
pView->m_hWnd,WM_SOCKET_MSG,FD_CLOSE);
pView->nNumConns++;
}
return 1;
}
  這里在accept ()后使用了WSAAsyncSelect()異步選擇函數(shù)。對于網(wǎng)絡(luò)事件的響應(yīng)最好采取異步選擇機制,只有采取這種方式才可以在由網(wǎng)絡(luò)對方所引起的不可預(yù)知的網(wǎng)絡(luò)事件發(fā)生時能馬上在進程中做出及時的響應(yīng)處理,而在沒有網(wǎng)絡(luò)事件到達時則可以處理其他事件,這種效率是很高的,而且完全符合Windows所標榜的消息觸發(fā)原則。WSAAsyncSelect()函數(shù)便是實現(xiàn)網(wǎng)絡(luò)事件異步選擇的核心函數(shù)。通過第四個參數(shù)FD_CLOSE注冊了應(yīng)用程序感興取的網(wǎng)絡(luò)事件是網(wǎng)絡(luò)斷開,當客戶方端開連接時該事件會被檢測到,同時會發(fā)出由第三個參數(shù)指定的自定義消息WM_SOCKET_MSG。

  5. 發(fā)送/接收

  當客戶機同服務(wù)器建立好連接后就可以通過send()/recv()函數(shù)進行發(fā)送和接收數(shù)據(jù)了,對于本程序只需在監(jiān)測到有撥號連接事件發(fā)生時向客戶機發(fā)送通知消息即可:

char buffer[1]={'a'};
send(newskt,buffer,1,0);//向客戶機發(fā)送字符a,表示現(xiàn)在服務(wù)器正在撥號。
  6. 關(guān)閉套接字

  在全部通訊完成之后,在退出程序之前需要調(diào)用closesocket();函數(shù)把創(chuàng)建的套接字關(guān)閉。

  (三)客戶機端的程序設(shè)計

  客戶機的編程要相對簡單許多,全部通訊過程只需以下四步:

  1. 創(chuàng)建套接字
  2. 建立連接
  3. 發(fā)送/接收
  4. 關(guān)閉套接字

  具體實現(xiàn)過程同服務(wù)器編程基本類似,只是由于需要接收數(shù)據(jù),因此待監(jiān)測的網(wǎng)絡(luò)事件為FD_CLOSE和FD_READ,在消息響應(yīng)函數(shù)中可以通過對消息參數(shù)的低位字節(jié)進行判定而區(qū)分出具體發(fā)生是何種網(wǎng)絡(luò)事件,并對其做出響應(yīng)的反應(yīng)。下面結(jié)合部分主要實現(xiàn)代碼對實現(xiàn)過程進行解釋:

……
m_ServIP=SERVERIP; //指定服務(wù)器的IP地址
m_Port=htons(USERPORT); //指定服務(wù)器的端口號
if((IPaddr=inet_addr(m_ServIP))==INADDR_NONE) //轉(zhuǎn)換成網(wǎng)絡(luò)地址
return FALSE;
else
{
sock=socket(AF_INET,SOCK_STREAM,0); //創(chuàng)建套接字
sockin.sin_family=AF_INET; //填充結(jié)構(gòu)
sockin.sin_addr.S_un.S_addr=IPaddr;
sockin.sin_port=m_Port;
connect(sock,(LPSOCKADDR)&sockin,sizeof(sockin)); //建立連接
//設(shè)定異步選擇事件
WSAAsyncSelect(sock,m_hWnd,WM_SOCKET_MSG,FD_CLOSEFD_READ);
//在這里可以通過震鈴、彈出對話框等方式通知客戶已經(jīng)連上服務(wù)器
}
……

//網(wǎng)絡(luò)事件的消息處理函數(shù)
int message=lParam & 0x0000FFFF;//取消息參數(shù)的低位
switch(message) //判定發(fā)生的是何種網(wǎng)絡(luò)事件
{
case FD_READ: //讀事件
AfxBeginThread(Read,NULL);
break;
case FD_CLOSE: //服務(wù)器關(guān)閉事件
……
break;
}

  在讀事件的消息處理過程中,單獨為讀處理過程開辟了一個線程,在該線程中接收從服務(wù)器發(fā)送過來的信息,并通過震鈴、彈出對話框等方式通知客戶端現(xiàn)在服務(wù)器正在撥號:

……
int a=recv(pView->sock,cDataBuffer,1,0); //接收從服務(wù)器發(fā)送來的消息
if(a>0)
AfxMessageBox("撥號連接已啟動!"); //通知用戶
…… QQread.com 推出Windows2003教程 win2003安裝介紹 win2003網(wǎng)絡(luò)優(yōu)化 win2003使用技巧 win2003系統(tǒng)故障 服務(wù)器配置 專家答疑
更多的請看:http://www.qqread.com/windows/2003/index.html  三、必要的完善

  前面只是介紹了程序設(shè)計的整體框架和設(shè)計思路,僅僅是一個雛形,有許多重要的細節(jié)沒有完善,不能用于實際使用。下面就對一些完全必要的細節(jié)做適當?shù)耐晟疲?br />
  (一) 界面的隱藏

  由于本程序系自動檢測、自動通知,完全不需要人工干預(yù),因此可以將其視為后臺運行的服務(wù)程序,因此程序主界面現(xiàn)在已無存在的必要,可以在應(yīng)用程序類的初始化實例函數(shù)InitInstance()中將ShowWindow();的參數(shù)SW_SHOW改成SW_HIDE即可。當需要有對話框彈出通知用戶時僅對話框出現(xiàn),主界面仍隱藏,因此是完全可行的。

  (二) 自啟動的實現(xiàn)

  由于服務(wù)端軟件需要時刻監(jiān)視有無進行撥號連接,所以必須具備自啟動的特性。而客戶端軟件由于接收消息和通知客戶都可以自動完成,因此假如能具備自啟動特性則可以完全脫離用戶的干預(yù)而取得較高的自動化程度。設(shè)置自啟動的特性,可以從以下幾個途徑加以考慮:

  1. 在"啟動"菜單上添加指向程序的快捷方式。
  
  2. 在Autoexec.bat中添加啟動程序的命令行。

  3. 在Win.ini中的[windows]節(jié)的run項目后添加程序路徑。

  4. 修改注冊表,添加鍵值的具體路徑為:

"HKEY_LOCAL_MACHINE/Software/Microsoft/Windows/CurrentVersion/Run"

  并將添加的鍵值修改為程序的存放路徑即可。以上幾種方法既可以手工添加,也可以通過編程使之自動完成。

  (三) 自動續(xù)聯(lián)

  對于服務(wù)/客戶模式的網(wǎng)絡(luò)通訊程序普遍要求服務(wù)端要先于客戶端運行,而本系統(tǒng)的客戶、服務(wù)端均為自啟動,不能保證服務(wù)器先于客戶機啟動,而且本系統(tǒng)要求只要客戶機和服務(wù)器連接在網(wǎng)絡(luò)上就要不間斷保持連接,因此需要使客戶和服務(wù)端都要具備自動續(xù)聯(lián)的功能。

  對于服務(wù)器端,當客戶端斷開時,需要關(guān)閉當前的套接字,并重新啟動一個新的套接字以等待客戶機的再次連接。這可以放在FD_CLOSE事件對應(yīng)的消息WM_SOCKET_MSG的消息響應(yīng)函數(shù)中來完成。而對于客戶端,假如先于服務(wù)器而啟動,則connect()函數(shù)將返回失敗,因此可以在程序啟動時用SetTimer()設(shè)置一個定時器,每隔一段時間(10秒)就試圖連接服務(wù)器一次,當connect()函數(shù)返回成功即服務(wù)器已啟動并與之連接上之后可以用KillTimer()函數(shù)將定時器關(guān)閉。另外當服務(wù)器關(guān)閉時需要再次開啟定時器,以確保當服務(wù)器再次運行時能與之建立連接,可以通過響應(yīng)FD_CLOSE事件來捕捉該事件的發(fā)生。

  小結(jié):本文通過Windows Sockets API實現(xiàn)了基于TCP/IP協(xié)議的面向連接的流式套接字的網(wǎng)絡(luò)通訊程序的設(shè)計,通過網(wǎng)絡(luò)通訊程序的支持可以把服務(wù)器捕捉到的撥號連接發(fā)生的事件及時通知給客戶端,最后通過對一些必要的細節(jié)的完善很好解決了在局域網(wǎng)上能及時得到服務(wù)器撥號連接的消息通知。本文所述程序在Windows 98 SE下,由Microsoft Visual C++ 6.0編譯通過;使用的代理服務(wù)器軟件為WinGate 4.3.0;上網(wǎng)方式為撥號上網(wǎng)。

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 平安县| 施甸县| 修水县| 靖宇县| 甘孜县| 丽江市| 无棣县| 讷河市| 乐昌市| 吴忠市| 布尔津县| 渑池县| 永德县| 麻江县| 米易县| 定兴县| 阿荣旗| 广河县| 会泽县| 封丘县| 富裕县| 永福县| 郧西县| 泸州市| 朔州市| 农安县| 六安市| 澄江县| 华亭县| 大田县| 云安县| 吴旗县| 麦盖提县| 甘南县| 库尔勒市| 丹寨县| 宜兰市| 嘉定区| 扶绥县| 平安县| 镇安县|