天天看點

XEIM 飛鴿傳書伺服器如何處理用戶端的資料

XEIM 服務端的 CXeimDlg 裡,有個函數用來專門處理 XEIM 用戶端資料的,函數原型:

LRESULT OnUserData(WPARAM wParam, LPARAM lParam);

根據以往的項目經驗,特别是在嵌入式項目中,前期的品質活動,其測試出企業即時通訊的成本明顯低于後期的品質活動,codereview的重要性怎麼強調都不過分,而單元測試在傳統開發流程中從時間順序上是排名第二的品質活動,也是一個非常重要的測試手段。既然前期的品質活動是如此的重要,何不把它們做到極限呢?這就引出了結對程式設計和飛鴿傳書。結對程式設計和飛鴿傳書給我們帶來了什麼?

這個函數處理網絡層收到的消息,我們這裡先不管網絡層如何實作(如果要了解網絡層實作,需要另外寫一個介紹文檔),我們隻讨論如何處理用戶端資料。

XEIM_Message xmsg(szData); 這個類把資料具體化,資料結構可以從這裡面了解到。

中這裡面,我們就可以擷取用戶端發過來的消息了:

char *Get_XEIM_Message();

通過判斷這個函數的傳回值,來對消息進行處理。

例如:

// 處理用戶端登入消息

if (! strcmp(xmsg.Get_XEIM_Message(), "login"))

{

ProcessLoginMessage(xmsg.GetData(), pContext);

} // END login

XEIM_Message 所帶的資料是可以自定義的,可以是字元串,可以是資料結構,總之,隻要是資料都可以。XEIM 最常用的是字元串,例如登入資料為:

"uid,password,ip,version",以逗号來分割每給字段。

一些函數的實作:

// XEIM 飛鴿傳書:http://www.freeeim.com/

// 處理用戶端資料

LRESULT CXeimDlg::OnUserData(WPARAM wParam, LPARAM lParam)

{

 char *szData = reinterpret_cast<char *>(wParam);

 unsigned int* piID = reinterpret_cast<unsigned int*>(lParam);

 ClientContext* pContext=NULL;

 // to be sure that pContext Suddenly does not dissapear..

// int nID;

 m_iocp.m_ContextMapLock.Lock();

 pContext=m_iocp.FindClient(*piID);

 m_iocp.m_ContextMapLock.Unlock();

 if(pContext!=NULL)

 {

  if (m_loop.ProcessMessage(szData, (unsigned)pContext))

  {

// AfxMessageBox("消息已在這裡處理了。");

  }

  else

  {

XEIM_Message xmsg(szData);

// 處理用戶端登入消息

if (! strcmp(xmsg.Get_XEIM_Message(), "login"))

{

 ProcessLoginMessage(xmsg.GetData(), pContext);

} // END login

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "contact")) // 讀取聯系人

{

 // 處理代碼比較多,是以開多一個函數

 ProcessContactMessage(pContext->m_Socket);

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "add")) // 添加聯系人

{

 if (!m_database.AddContact((LPSTR)(m_users.GetUser(pContext->m_Socket)->GetUID()), xmsg.GetData())) // 添加失敗

 {

  XEIM_Message toSend("addfailed",(char*)m_database.m_strLastError.c_str());

  m_iocp.BuildPackageAndSend(pContext->m_Socket,Job_UserData,toSend.GetBuffer());

 // AfxMessageBox("asdf");

 }

 else // 添加成功

 {//AfxMessageBox("添加成功");

 // char *szChunk = m_database.GetContactChunk(m_users.GetUser(pContext->m_Socket)->GetUID(), xmsg.GetData());

  char *szChunk = m_database.GetUserInfo(xmsg.GetData());

  if (NULL != szChunk)

  {

XEIM_Message toSend("addok",szChunk);

  // AfxMessageBox(toSend.GetBuffer());

m_iocp.BuildPackageAndSend(pContext->m_Socket,Job_UserData,toSend.GetBuffer());

delete szChunk;

  }

 }

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "forward")) // 轉發文字消息

{

 CXEIM_Text xText(xmsg.GetData());

 ProcessForwardMessage(xText, pContext->m_Socket);

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "offline")) // 用戶端請求離線消息

{

 ProcessOfflineRequest(pContext->m_Socket);

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "userinfo")) // 用戶端請求使用者資訊

{

 ProcessUserInfo(pContext->m_Socket, xmsg.GetData());

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "cmdline")) // 指令行

{

 CXEIM_Text xText(xmsg.GetData());

 ProcessCmdMessage(xText, pContext->m_Socket);

}

//

else if (! strcmp(xmsg.Get_XEIM_Message(), "cmdreturn")) // 指令行傳回

{

 CXEIM_Text xText(xmsg.GetData());

// AfxMessageBox("asdfasf");

 ProcessForwardMessage(xText, pContext->m_Socket, "cmdreturn");

}

///

else if (! _tcscmp(xmsg.Get_XEIM_Message(), "historytree"))//聊天管理器的樹型資料

{

 ProcessHistoryTree(pContext->m_Socket, xmsg.GetData());

}

///

else if (! _tcscmp(xmsg.Get_XEIM_Message(), "historychat"))//聊天記錄

{

 string strOneUser, strTwoUser, strLastTime;

 stringstream ssmsg(xmsg.GetData());

 ssmsg >> strOneUser;

 ssmsg >> strTwoUser;

 ssmsg >> strLastTime;

 ProcessHistoryChat(pContext->m_Socket, strOneUser.c_str(),

strTwoUser.c_str(), strLastTime.c_str());

}

else if (! _tcscmp(xmsg.Get_XEIM_Message(), "ready to quit")) // 使用者在其他地方登陸後,确認退出。

{

 m_users.RemoveUser(pContext->m_Socket);

 m_iocp.DisconnectClient(pContext->m_Socket); // 把在其他地方登陸的連結斷開。

 // 删除資訊,這樣才能判斷是在其他地方登陸,OnClientDisconnected 裡面有處理。

}

  }

 }

 delete [] szData;

 delete piID;

 return 0;

}

繼續閱讀