網(wǎng)絡(luò)服務(wù)器的編寫相對(duì)客戶端的網(wǎng)絡(luò)應(yīng)用較為復(fù)雜,既要實(shí)現(xiàn)單個(gè)客戶端的功能,也要實(shí)現(xiàn)其管理,包括應(yīng)答,讀/寫數(shù)據(jù)的線程開啟/回收,多線之間的數(shù)據(jù)互斥等.(管理方面是采用了一個(gè)非開源項(xiàng)目的代碼,所以代碼暫不便公開,將以LIB方式提供大家使用.)為方便后臺(tái)服務(wù)的開發(fā),因此采用了MFC框架.范例中代碼較為多不一一進(jìn)行說明,只從大體上簡(jiǎn)單介紹每個(gè)類的作,并針對(duì)網(wǎng)絡(luò)相關(guān)部分進(jìn)行相關(guān)說明.
范例是實(shí)現(xiàn)一個(gè)消息管理服務(wù).提供群發(fā)或定向發(fā)送文本消息至客戶端,并帶有服務(wù)啟動(dòng)/關(guān)閉,日志記錄的功能.
CServerDlg是服務(wù)器操作界面,界面及功能說明如下圖所示:
CSystemOptionDlg是服務(wù)器的設(shè)置選項(xiàng)對(duì)話框.服務(wù)器方面同時(shí)提供了網(wǎng)絡(luò),數(shù)據(jù)庫,計(jì)時(shí)器3種引擎的調(diào)用,因此可設(shè)置實(shí)際中是否應(yīng)用,若要使用則必需設(shè)定相關(guān)的參數(shù).
CInitParamter負(fù)責(zé)服務(wù)器參數(shù)的保存/讀取,并允許由其它類直接訪問內(nèi)置的變量值.數(shù)據(jù)會(huì)自動(dòng)保存在注冊(cè)表的:HKEY_CURRENT_USER\\Software\\OGF\\GameServer
CGameService是服務(wù)器的流程執(zhí)行的框架,負(fù)責(zé)按指定的流程對(duì)內(nèi)核服務(wù)的初始化,可完全復(fù)雜使用.
CDataBaseSink是數(shù)據(jù)庫處理的鉤子類,負(fù)責(zé)實(shí)現(xiàn)服務(wù)器所需的數(shù)據(jù)庫操作.(但不是本例的重點(diǎn),且沒有使用的成分,所以不作詳解)
AttemperEnginerSink負(fù)責(zé)服務(wù)器管理的協(xié)調(diào)處理,同時(shí),也是各種消息的回調(diào)接口.本例中用到的是網(wǎng)絡(luò)的應(yīng)答,讀取和關(guān)閉事件.其相關(guān)代碼如下:
//網(wǎng)絡(luò)應(yīng)答事件
bool __cdecl CAttemperEngineSink::OnEventSocketAccept(NTY_SocketAcceptEvent * pSocketAcceptEvent)
{
ASSERT(m_pServerDlgSink);
if(m_pServerDlgSink){
//轉(zhuǎn)換為IP字串
in_addr SocketAddr;
SocketAddr.S_un.S_addr = pSocketAcceptEvent->dwClientIP;
CString szClientIP;
szClientIP.Format("%s - %d", inet_ntoa(SocketAddr), pSocketAcceptEvent->wIndex);
//添加至客戶端列表
int nIndex = m_pServerDlgSink->m_ClientList.InsertString(-1, szClientIP);
m_pServerDlgSink->m_ClientList.SetItemData(nIndex, MAKELONG(pSocketAcceptEvent->wIndex, pSocketAcceptEvent->wRoundID));
//設(shè)置允許被群發(fā)
m_pITCPSocketEngine->AllowBatchSend(pSocketAcceptEvent->wIndex, pSocketAcceptEvent->wRoundID, true);
}
return true;
}
//網(wǎng)絡(luò)讀取事件
bool __cdecl CAttemperEngineSink::OnEventSocketRead(CMD_Command Command, void * pDataBuffer, WORD wDataSize, NTY_SocketReadEvent * pSocketReadEvent)
{
//網(wǎng)絡(luò)消息處理
switch (Command.wMainCmdID)
{
//自定義的消息體
case 10049:
{
if(Command.wSubCmdID==2||Command.wSubCmdID==4){
//將讀取的內(nèi)容寫入日志框
CString szTemp;
CString szRecv = (LPCTSTR)pDataBuffer;
CEdit* pEdit = (CEdit*)m_pServerDlgSink->GetDlgItem(IDC_EDIT_RECV);
pEdit->GetWindowText(szTemp);
szTemp += "\r\n";
szTemp += szRecv;
pEdit->SetWindowText(szTemp);
}
return true;
}
}
//if unknow command, will close the socket connect!!!
return false;
}
//網(wǎng)絡(luò)關(guān)閉事件
bool __cdecl CAttemperEngineSink::OnEventSocketClose(NTY_SocketCloseEvent * pSocketCloseEvent)
{
LONG l = MAKELONG(pSocketCloseEvent->wIndex, pSocketCloseEvent->wRoundID);
//枚舉所有列表項(xiàng),找出相同網(wǎng)絡(luò)標(biāo)識(shí),將其刪除
for(int nIndex=0;nIndex<m_pServerDlgSink->m_ClientList.GetCount();nIndex++){
if(m_pServerDlgSink->m_ClientList.GetItemData(nIndex)==l){
m_pServerDlgSink->m_ClientList.DeleteString(nIndex);
break;
}
}
return true;
}
//發(fā)送文本
bool CAttemperEngineSink::SendText()
{
m_pServerDlgSink->UpdateData();
//獲取接收客戶端的標(biāo)識(shí),找不到則進(jìn)行群發(fā)
//nIndex, nRoundID是客戶端連上服務(wù)器時(shí)記錄的標(biāo)識(shí),不能單一作判斷使用
int nIndex = INDEX_ALL_SOCKET;
int nRoundID = 0;
if(m_pServerDlgSink->m_ClientList.GetCurSel()!=LB_ERR){
LONG l = m_pServerDlgSink->m_ClientList.GetItemData(m_pServerDlgSink->m_ClientList.GetCurSel());
nIndex = l & 0xFFFF;
nRoundID = l>>16;
}
//發(fā)送消息
m_pITCPSocketEngine->SendData(nIndex, nRoundID, 10049, 3, (LPVOID)((LPCTSTR)m_pServerDlgSink->m_SendText), m_pServerDlgSink->m_SendText.GetLength()+1);
return true;
}
運(yùn)行結(jié)果:

操~~~,CSDN是什么垃圾,竟然文章保存后是顯示柳傳志,又要我重寫,氣死我了!
網(wǎng)絡(luò)應(yīng)用范例代碼:
http://dl2.csdn.net/down4/20070725/25000917122.rar
網(wǎng)絡(luò)應(yīng)用范例運(yùn)行程序:
http://dl2.csdn.net/down4/20070725/25000851623.rar