網絡服務器的編寫相對客戶端的網絡應用較為復雜,既要實現單個客戶端的功能,也要實現其管理,包括應答,讀/寫數據的線程開啟/回收,多線之間的數據互斥等.(管理方面是采用了一個非開源項目的代碼,所以代碼暫不便公開,將以LIB方式提供大家使用.)為方便后臺服務的開發,因此采用了MFC框架.范例中代碼較為多不一一進行說明,只從大體上簡單介紹每個類的作,并針對網絡相關部分進行相關說明.
范例是實現一個消息管理服務.提供群發或定向發送文本消息至客戶端,并帶有服務啟動/關閉,日志記錄的功能.
CServerDlg是服務器操作界面,界面及功能說明如下圖所示:
CSystemOptionDlg是服務器的設置選項對話框.服務器方面同時提供了網絡,數據庫,計時器3種引擎的調用,因此可設置實際中是否應用,若要使用則必需設定相關的參數.
CInitParamter負責服務器參數的保存/讀取,并允許由其它類直接訪問內置的變量值.數據會自動保存在注冊表的:HKEY_CURRENT_USER\\Software\\OGF\\GameServer
CGameService是服務器的流程執行的框架,負責按指定的流程對內核服務的初始化,可完全復雜使用.
CDataBaseSink是數據庫處理的鉤子類,負責實現服務器所需的數據庫操作.(但不是本例的重點,且沒有使用的成分,所以不作詳解)
AttemperEnginerSink負責服務器管理的協調處理,同時,也是各種消息的回調接口.本例中用到的是網絡的應答,讀取和關閉事件.其相關代碼如下:
//網絡應答事件
bool __cdecl CAttemperEngineSink::OnEventSocketAccept(NTY_SocketAcceptEvent * pSocketAcceptEvent)
{
ASSERT(m_pServerDlgSink);
if(m_pServerDlgSink){
//轉換為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));
//設置允許被群發
m_pITCPSocketEngine->AllowBatchSend(pSocketAcceptEvent->wIndex, pSocketAcceptEvent->wRoundID, true);
}
return true;
}
//網絡讀取事件
bool __cdecl CAttemperEngineSink::OnEventSocketRead(CMD_Command Command, void * pDataBuffer, WORD wDataSize, NTY_SocketReadEvent * pSocketReadEvent)
{
//網絡消息處理
switch (Command.wMainCmdID)
{
//自定義的消息體
case 10049:
{
if(Command.wSubCmdID==2||Command.wSubCmdID==4){
//將讀取的內容寫入日志框
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;
}
//網絡關閉事件
bool __cdecl CAttemperEngineSink::OnEventSocketClose(NTY_SocketCloseEvent * pSocketCloseEvent)
{
LONG l = MAKELONG(pSocketCloseEvent->wIndex, pSocketCloseEvent->wRoundID);
//枚舉所有列表項,找出相同網絡標識,將其刪除
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;
}
//發送文本
bool CAttemperEngineSink::SendText()
{
m_pServerDlgSink->UpdateData();
//獲取接收客戶端的標識,找不到則進行群發
//nIndex, nRoundID是客戶端連上服務器時記錄的標識,不能單一作判斷使用
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;
}
//發送消息
m_pITCPSocketEngine->SendData(nIndex, nRoundID, 10049, 3, (LPVOID)((LPCTSTR)m_pServerDlgSink->m_SendText), m_pServerDlgSink->m_SendText.GetLength()+1);
return true;
}
運行結果:

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