IOCP局域網(wǎng)監(jiān)控研究論文

時(shí)間:2022-03-12 09:51:00

導(dǎo)語:IOCP局域網(wǎng)監(jiān)控研究論文一文來源于網(wǎng)友上傳,不代表本站觀點(diǎn),若需要原創(chuàng)文章可咨詢客服老師,歡迎參考。

IOCP局域網(wǎng)監(jiān)控研究論文

摘要本文介紹了一種在WINDOWS平臺(tái)上比較成熟的I/O方法---完成端口,提出了通過使用iocp機(jī)制和旁視列表技術(shù)建立網(wǎng)絡(luò)服務(wù)器模型的方法,實(shí)現(xiàn)了利用為數(shù)不多的線程為成千上萬的客戶同時(shí)提供網(wǎng)絡(luò)服務(wù),解決了大多數(shù)網(wǎng)絡(luò)服務(wù)器連接大量客戶端和處理大量數(shù)據(jù)時(shí)存在的問題,獲得了極好的性能和強(qiáng)大的擴(kuò)展能力。文章給出了基于Windows2000平臺(tái)的局域網(wǎng)監(jiān)控系統(tǒng)中網(wǎng)絡(luò)服務(wù)器的設(shè)計(jì)與實(shí)現(xiàn)過程。

關(guān)鍵詞完成端口;旁視列表;網(wǎng)絡(luò)服務(wù)器;VC++

1引言

在局域網(wǎng)遠(yuǎn)程監(jiān)控系統(tǒng)中,網(wǎng)絡(luò)管理中心需要同時(shí)監(jiān)控每個(gè)客戶端計(jì)算機(jī)的運(yùn)行情況,將遠(yuǎn)程監(jiān)控畫面顯示在管理中心的電腦屏幕上。網(wǎng)絡(luò)服務(wù)器要求實(shí)現(xiàn)定時(shí)截獲客戶端計(jì)算機(jī)上的屏幕數(shù)據(jù)與正在運(yùn)行程序的數(shù)據(jù),定時(shí)截取客戶端屏幕圖像,并將截獲的數(shù)據(jù)和圖像保存在數(shù)據(jù)庫中等功能。在較大型局域網(wǎng)中有幾百上千個(gè)客戶端,需要對大量的客戶端數(shù)據(jù)進(jìn)行處理。因此如何讓網(wǎng)絡(luò)服務(wù)器同時(shí)為多個(gè)客戶端服務(wù),但又不喪失整體的性能成為開發(fā)的難點(diǎn)。本文采用了I/O完成端口、旁視列表等技術(shù),設(shè)計(jì)了一種高效的網(wǎng)絡(luò)服務(wù)器,讓此問題得到了有效的解決。

2IOCP機(jī)制

IOCP(I/OCompletionPort輸入/輸出完成端口)是一種能夠合理利用與管理多線程的機(jī)制。該機(jī)制使用完成端口,用一定數(shù)量的線程處理重疊I/O(OverlappedI/O)的技術(shù),幫助處理大量客戶端請求的網(wǎng)絡(luò)服務(wù)問題,特別適合于開發(fā)網(wǎng)絡(luò)服務(wù)器一類的應(yīng)用程序,并可使系統(tǒng)的性能達(dá)到較佳狀態(tài)。IOCP模型圖如圖1所示。

圖1完成端口工作模式

完成端口模式要求創(chuàng)建一個(gè)Win32完成端口對象來對重疊I/O請求進(jìn)行管理,并通過創(chuàng)建一定數(shù)量的工作者線程(WorkThread),來為已經(jīng)完成的重疊I/O請求提供服務(wù)。其實(shí),可以把完成端口看成系統(tǒng)維護(hù)的一個(gè)隊(duì)列,操作系統(tǒng)把重疊I/O操作完成的事件通知放入該隊(duì)列,由于是“操作完成”的事件通知,故取名為“完成端口”。一個(gè)完成端口被創(chuàng)建以后,可以和多個(gè)文件句柄進(jìn)行關(guān)聯(lián)(文件句柄可以是真正的文件句柄,也可以是Socket句柄或命名管道),并在關(guān)聯(lián)后的句柄上進(jìn)行重疊I/O操作。當(dāng)I/O操作完成后,一個(gè)重疊I/O完成的事件通知就會(huì)被排在此端口的完成隊(duì)列上,此時(shí),某個(gè)工作者線程將會(huì)被喚醒來為完成端口服務(wù),執(zhí)行特定的處理工作。一般來說,一個(gè)應(yīng)用程序可以創(chuàng)建多個(gè)工作者線程來處理完成端口上的通知事件,工作者線程的數(shù)量依賴于程序的具體需要。

3數(shù)據(jù)庫同步機(jī)制實(shí)現(xiàn)過程:

(系統(tǒng)結(jié)構(gòu)圖如圖2)

圖2系統(tǒng)結(jié)構(gòu)圖

(1)整體系統(tǒng)安裝初始,各個(gè)同步端的數(shù)據(jù)庫初始化為一致。

(2)數(shù)據(jù)服務(wù)器維護(hù)各個(gè)同步端的SQL隊(duì)列,不斷檢查是否有操作項(xiàng),然后將各項(xiàng)操作依序發(fā)送至各個(gè)在線的同步端。

(3)在線同步端收到后,置入SQL隊(duì)列,將SQL隊(duì)列按操作發(fā)生時(shí)間先后排序

(4)在線同步端將SQL隊(duì)列中的各項(xiàng)操作依序執(zhí)行并通知服務(wù)器執(zhí)行的結(jié)果。服務(wù)器收到后將該項(xiàng)操作從該同步端的SQL隊(duì)列中刪除。

(5)某一在線同步端執(zhí)行非讀的SQL操作后,向服務(wù)器發(fā)送該操作,服務(wù)器將該操作放入除了此同步端外的其他同步端的SQL隊(duì)列中,并放入歷史SQL文件,然后轉(zhuǎn)到第2步

(6)有新同步端注冊入系統(tǒng)后,將從數(shù)據(jù)服務(wù)器(數(shù)據(jù)服務(wù)器同時(shí)建立該同步端的SQL隊(duì)列)下載歷史SQL文件,并執(zhí)行其中各項(xiàng)操作。

(7)某同步端選擇注銷,數(shù)據(jù)服務(wù)器刪除該同步端的SQL隊(duì)列。

4內(nèi)存分配機(jī)制

在該系統(tǒng)中內(nèi)存的分配和釋放比較頻繁,為了比較高效分配釋放數(shù)據(jù),采用一種稱作LookasideList(旁視列表)的數(shù)據(jù)結(jié)構(gòu)。在該系統(tǒng)中用于單句柄數(shù)據(jù)和重疊操作數(shù)據(jù)(完成鍵)的分配和釋放。LookasideList的原理是在分配一塊數(shù)據(jù)空間前,先查看回收鏈表中是否有數(shù)據(jù)空間指針,如果有則不需要調(diào)用系統(tǒng)的內(nèi)存分配,直接使用回收鏈表中的該指針指向的數(shù)據(jù)空間,并將回收鏈表中該指針節(jié)點(diǎn)移除,當(dāng)使用完數(shù)據(jù)空間后,也不必調(diào)系統(tǒng)的內(nèi)存釋放,而將該數(shù)據(jù)空間指針移入回收鏈表。在進(jìn)程最終結(jié)束后才將回收鏈表中的所有指針指向的數(shù)據(jù)空間釋放。從而大大減低程序在運(yùn)行期的頻繁內(nèi)存分配和釋放產(chǎn)生的開銷。

5實(shí)現(xiàn)過程

5.1初始化

讀取服務(wù)器配置文件,初始化客戶端連接鏈表;建立完成端口,根據(jù)CPU個(gè)數(shù)建立等待和接受完成通知的線程;初始化WinSock接口,建立偵聽SOCKET;取擴(kuò)展函數(shù)AcceptEx;關(guān)聯(lián)完成端口到偵聽SOCKET;綁定和偵聽。

5.2啟動(dòng)服務(wù)

(1)建立網(wǎng)絡(luò)事件、設(shè)置該網(wǎng)絡(luò)事件為偵聽SOCKET的ACCEPT網(wǎng)絡(luò)事件,這樣當(dāng)AcceptEx一次性分配的N個(gè)預(yù)備SOCKET由于滿足不斷上來的TCP連接而耗盡,并有新的TCP連接請求時(shí),就會(huì)觸發(fā)偵聽SOCKET的ACCEPT事件,服務(wù)器就會(huì)在這個(gè)時(shí)機(jī)調(diào)用AcceptEx再次分配N個(gè)新的預(yù)備SOCKET以滿足新的TCP連接請求。在該系統(tǒng)中,N=10。

(2)分配的N個(gè)預(yù)備SOCKET

(3)建立檢查和分配線程,該線程作用:等待ACCEPT網(wǎng)絡(luò)事件以分配新的預(yù)備SOCKET;定時(shí)檢測和掛斷未收發(fā)任何數(shù)據(jù)且超時(shí)連接的TCP連接,防止DoS(拒絕服務(wù))攻擊。

5.3完成通知線程內(nèi)部處理

while(TRUE)

{

//等待完成端口的通知

bSuccess=GetQueuedCompletionStatus(

pThis->m_hCOP,

&dwNumberBytes,

(PULONG_PTR)&lpHandleContext,

&lpOverlapped,

INFINITE

);

if(!bSuccess)

{

pThis->m_strLog.Format("GetQueuedCompletionStatus()失敗:%d",GetLastError());

Log(pThis->m_strLog);

PPER_IO_CONTEXTlpPerIoContext=(PPER_IO_CONTEXT)lpOverlapped;

lpPerIoContext->pNext=NULL;

pThis->InsertToLookaside(lpPerIoContext,NULL);

lpHandleContext->pNext=NULL;

pThis->InsertToLookaside(NULL,lpHandleContext);

continue;

}

//如果外部發(fā)送空的單句柄數(shù)據(jù)指針,則退出完成通知線程

if(NULL==lpHandleContext)

{

return0;

}

//將完成鍵轉(zhuǎn)換為自己格式的數(shù)據(jù)指針

PPER_IO_CONTEXTlpPerIoContext=(PPER_IO_CONTEXT)lpOverlapped;

//這種情況表示客戶端自己掛斷連接

if(IoAccept!=lpPerIoContext->IoOperation)

{

if(0==dwNumberBytes)

{

shutdown(lpPerIoContext->sClient,SD_BOTH);

closesocket(lpPerIoContext->sClient);

lpPerIoContext->pNext=NULL;

pThis->InsertToLookaside(lpPerIoContext,NULL);

lpHandleContext->pNext=NULL;

pThis->InsertToLookaside(NULL,lpHandleContext);

pThis->DecreaseClientNum();

continue;

}

}

HANDLEhResult;

PPER_HANDLE_CONTEXTlpNewperHandleContext;

//判斷該通知為哪種類型的操作的結(jié)果

switch(lpPerIoContext->IoOperation)

{

//接受新的TCP連接

caseIoAccept:

pThis->IncreaseClientNum();

EnterCriticalSection(&pThis->m_ListCriSection);

pThis->ReleaseConnectionNode

(lpPerIoContext);

LeaveCriticalSection(&pThis->m_ListCriSection);

//將偵聽SOCKET的屬性復(fù)制給客戶端SOCKET,因?yàn)閍ccept創(chuàng)建的socket會(huì)自動(dòng)繼承偵聽socket的屬性,而AcceptEx不會(huì)

nResult=setsockopt(

lpPerIoContext->sClient,

SOL_SOCKET,

SO_UPDATE_ACCEPT_CONTEXT,

(char*)&pThis->m_ListenSocket,

sizeof(pThis->m_ListenSocket)

);

if(SOCKET_ERROR==nResult)

{

pThis->m_strLog.Format("客戶(ID=%d)SO_UPDATE_ACCEPT_CONTEXT失敗:%d",

lpPerIoContext->unId,WSAGetLastError());

Log(pThis->m_strLog);

closesocket(lpPerIoContext->sClient);

lpPerIoContext->pNext=NULL;

pThis->InsertToLookaside(lpPerIoContext,NULL);

pThis->DecreaseClientNum();

continue;

}

//為新的SOCKET分配單句柄數(shù)據(jù)

lpNewperHandleContext=pThis->GetHandleFromLookaside();

if(NULL==lpNewperHandleContext)

{

lpNewperHandleContext=(PPER_HANDLE_CONTEXT)HeapAlloc(

GetProcessHeap(),

HEAP_ZERO_MEMORY,

sizeof(PER_HANDLE_CONTEXT)

);

if(NULL==lpNewperHandleContext)

{

pThis->m_strLog.Format("HeapAlloc()失敗");

Log(pThis->m_strLog);

shutdown(lpPerIoContext->sClient,SD_BOTH);

closesocket(lpPerIoContext->sClient);

lpPerIoContext->pNext=NULL;

pThis->InsertToLookaside(lpPerIoContext,NULL);

pThis->DecreaseClientNum();

continue;

}

}

//將新的SOCKET關(guān)聯(lián)到同一完成端口上

lpNewperHandleContext->IoSocket=lpPerIoContext->sClient;

lpNewperHandleContext->pNext=NULL;

hResult=CreateIoCompletionPort(

(HANDLE)lpPerIoContext->sClient,\

pThis->m_hCOP,

(DWORD_PTR)lpNewperHandleContext,

);

if(NULL==hResult)

{

pThis->m_strLog.Format("關(guān)聯(lián)完成端口到客戶套接字失敗:%d",GetLastError());

Log(pThis->m_strLog);

shutdown(lpPerIoContext->sClient,SD_BOTH);

closesocket(lpPerIoContext->sClient);

lpPerIoContext->pNext=NULL;

lpNewperHandleContext->pNext=NULL;

pThis->InsertToLookaside(lpPerIoContext,NULL);

pThis->InsertToLookaside(NULL,lpNewperHandleContext);

pThis->DecreaseClientNum();

continue;

}

//接收來自CLIENT的數(shù)據(jù)

if(pThis->HandleData(lpPerIoContext,IO_READ_COMPLETION,dwNumberBytes))

pThis->DataAction(lpPerIoContext,lpNewperHandleContext);

continue;

//數(shù)據(jù)接收完的通知

caseIoRead:

if(pThis->HandleData(lpPerIoContext,IO_READ_COMPLETION,dwNumberBytes))

pThis->DataAction(lpPerIoContext,lpNewperHandleContext);

continue;

//數(shù)據(jù)發(fā)送完的通知

caseIoWrite:

if(pThis->HandleData(lpPerIoContext,IO_WRITE_COMPLETION,dwNumberBytes))

pThis->DataAction(lpPerIoContext,lpNewperHandleContext);

continue;

default:

continue;

}

}

數(shù)據(jù)處理都放在HandleData中實(shí)現(xiàn),數(shù)據(jù)處理完后的響應(yīng)代碼都在DataAction中實(shí)現(xiàn),在此不做詳細(xì)介紹。

6結(jié)束語

編寫網(wǎng)絡(luò)服務(wù)器應(yīng)用程序的難點(diǎn)在于程序的“可擴(kuò)展性”,即如何開發(fā)出大容量且能處理大量并發(fā)SocketI/O請求的高性能應(yīng)用程序。IOCP機(jī)制通過完成端口對象來對重疊I/O請求進(jìn)行管理,并且利用多線程來處理重疊I/O操作完成后得到的數(shù)據(jù),是一種與Win32Sockets結(jié)合度較高的實(shí)現(xiàn)高效率I/O的有效方法。

本文設(shè)計(jì)的網(wǎng)絡(luò)服務(wù)器在局域網(wǎng)監(jiān)控系統(tǒng)中成功使用。實(shí)際應(yīng)用表明:利用IOCP機(jī)制實(shí)現(xiàn)的網(wǎng)絡(luò)服務(wù)器應(yīng)用程序能夠針對大量的客戶請求進(jìn)行高效處理,在速度和性能上體現(xiàn)出其良好的特征,不失為一種實(shí)現(xiàn)網(wǎng)絡(luò)服務(wù)器的有效技術(shù)。

參考文獻(xiàn)

[1]張靜華,張玉明.IOCP研究及在大規(guī)模網(wǎng)絡(luò)通信系統(tǒng)中的應(yīng)用.計(jì)算機(jī)與現(xiàn)代化,2004,9

[2]陳和平,周靜寧等.IOCP機(jī)制與網(wǎng)絡(luò)服務(wù)器實(shí)現(xiàn)方法.計(jì)算機(jī)應(yīng)用,2003,4

[3]AnthonyJones,JimOhlund著.Windows網(wǎng)絡(luò)編程技術(shù).機(jī)械工業(yè)出版社,2000,(176-206)

[4]潘愛民,王國印譯.VisualC++技術(shù)內(nèi)幕(第四版).清華大學(xué)出版社,1999

[5]官章全,韓云君等.VisualC++6.0高級(jí)編程范例.電子工業(yè)出版社,2001