Windows CE 下的 TCP 服務(wù)器端類
與上一個帖子對應(yīng),可以互相通訊。
頭文件:
//?TCPCustom_CE.h:?interface?for?the?CTCPCustom_CE?class. // ////////////////////////////////////////////////////////////////////// #if?!defined(AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_) #define?AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_ #if?_MSC_VER?>?1000 #pragma?once #endif?//?_MSC_VER?>?1000 #include#include?"TCPServer_CE.h" class?CTCPCustom_CE?? { public: CTCPCustom_CE(); virtual?~CTCPCustom_CE(); public: CTCPServer_CE?*?m_pTCPServer_CE;?//引用TCP服務(wù)端監(jiān)聽Socket CString?m_RemoteHost;?//遠(yuǎn)程主機(jī)IP地址 DWORD?m_RemotePort;?//遠(yuǎn)程主機(jī)端口號 SOCKET?m_socket;??????//通訊Socket句柄 private: HANDLE?m_exitThreadEvent;??//通訊線程退出事件句柄 HANDLE?m_tcpThreadHandle;??//通訊線程句柄 private: ????//通訊線程函數(shù) static?DWORD?SocketThreadFunc(PVOID?lparam); public: //打開socket,創(chuàng)建通訊線程 bool?Open(CTCPServer_CE?*pTCPServer); ???? //關(guān)閉socket,關(guān)閉線程,釋放Socket資源 bool?Close(); //向客戶端發(fā)送數(shù)據(jù) bool??SendData(const?char?*?buf?,?int?len); }; #endif?//?!defined(AFX_TCPCUSTOM_CE_H__0E8B4A18_8A99_438E_B5F6_B5985FFC117D__INCLUDED_)
源文件:
//?TCPCustom_CE.cpp:?implementation?of?the?CTCPCustom_CE?class. // ////////////////////////////////////////////////////////////////////// #include?"stdafx.h" #include?"TCPServer.h" #include?"TCPCustom_CE.h" #ifdef?_DEBUG #undef?THIS_FILE static?char?THIS_FILE[]=__FILE__; #define?new?DEBUG_NEW #endif ////////////////////////////////////////////////////////////////////// //?Construction/Destruction ////////////////////////////////////////////////////////////////////// //構(gòu)造函數(shù) CTCPCustom_CE::CTCPCustom_CE() { ???//創(chuàng)建線程退出事件 ???m_exitThreadEvent?=?CreateEvent(NULL,FALSE,FALSE,NULL); } //析構(gòu)函數(shù) CTCPCustom_CE::~CTCPCustom_CE() { ???//關(guān)閉線程退出事件 ???CloseHandle(m_exitThreadEvent); } /*-------------------------------------------------------------------- 【函數(shù)介紹】:??此線程用于監(jiān)聽與客戶端連接的socket通訊的事件,例如當(dāng)接收到數(shù)據(jù)、 ???連接斷開和通訊過程發(fā)生錯誤等事件 【入口參數(shù)】:??lparam:無類型指針,可以通過此參數(shù),向線程中傳入需要用到的資源。 ???在這里我們將CTCPCustom_CE類實例指針傳進(jìn)來 【出口參數(shù)】:??(無) 【返回??值】:??返回值沒有特別的意義,在此我們將返回值設(shè)為0。 ---------------------------------------------------------------------*/ DWORD?CTCPCustom_CE::SocketThreadFunc(PVOID?lparam) { CTCPCustom_CE?*pSocket; //得到CTCPCustom類實例指針 pSocket?=?(CTCPCustom_CE*)lparam; //定義讀事件集合 fd_set?fdRead;?? int?ret; TIMEVAL aTime; aTime.tv_sec?=?1; aTime.tv_usec?=?0; while?(TRUE) { ????????//收到退出事件,結(jié)束線程 if?(WaitForSingleObject(pSocket->m_exitThreadEvent,0)?==?WAIT_OBJECT_0) { break; } //置空讀事件集合 FD_ZERO(&fdRead); //給pSocket設(shè)置讀事件 FD_SET(pSocket->m_socket,&fdRead); //調(diào)用select函數(shù),判斷是否有讀事件發(fā)生 ret?=?select(0,&fdRead,NULL,NULL,&aTime); if?(ret?==?SOCKET_ERROR) { //觸發(fā)錯誤事件 pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,1); //關(guān)閉socket closesocket(pSocket->m_socket); break; } if?(ret?>?0) { //判斷是否讀事件 if?(FD_ISSET(pSocket->m_socket,&fdRead)) { char?recvBuf[1024]; int?recvLen; ZeroMemory(recvBuf,1024); recvLen?=?recv(pSocket->m_socket,recvBuf,?1024,0);? if?(recvLen?==?SOCKET_ERROR) { int?nErrorCode?=?WSAGetLastError(); //觸發(fā)與客戶端端連接的Socket錯誤 pSocket->m_pTCPServer_CE->OnClientError(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,nErrorCode); //觸發(fā)與客戶端端連接的Socket關(guān)閉事件 pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket); //關(guān)閉socket closesocket(pSocket->m_socket); break; } //表示連接已經(jīng)從容關(guān)閉 else?if?(recvLen?==?0) { pSocket->m_pTCPServer_CE->OnClientClose(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket); //關(guān)閉socket closesocket(pSocket->m_socket); break; } else { ???//觸發(fā)與客戶端端連接的Socket讀事件 ???????????????????pSocket->m_pTCPServer_CE->OnClientRead(pSocket->m_pTCPServer_CE->m_pOwnerWnd,pSocket,recvBuf,recvLen); } } } } return?0; } /*-------------------------------------------------------------------- 【函數(shù)介紹】:?打開socket,創(chuàng)建通訊線程 【入口參數(shù)】:??pTCPServer指向服務(wù)器端監(jiān)聽socket 【出口參數(shù)】:??(無) 【返回??值】:??TRUE:打開成功;FALSE:打開失敗 ---------------------------------------------------------------------*/ bool?CTCPCustom_CE::Open(CTCPServer_CE?*pTCPServer) { ???//創(chuàng)建通訊線程 ???m_tcpThreadHandle?=?CreateThread(NULL,0,SocketThreadFunc,this,0,NULL); ???if?(m_tcpThreadHandle?==?NULL) ???{ ???closesocket(m_socket); ???return?FALSE; ???} ???//設(shè)置通訊模式為異步模式 ???DWORD?ul=?1; ???ioctlsocket(m_socket,FIONBIO,&ul); ???m_pTCPServer_CE?=?pTCPServer; ???return?TRUE; } /*-------------------------------------------------------------------- 【函數(shù)介紹】:?關(guān)閉socket,關(guān)閉線程,釋放Socket資源 【入口參數(shù)】:??(無) 【出口參數(shù)】:??(無) 【返回??值】:??TRUE:成功關(guān)閉;FALSE:關(guān)閉失敗 ---------------------------------------------------------------------*/ bool?CTCPCustom_CE::Close() { ???//發(fā)送通訊線程結(jié)束事件 ???SetEvent(m_exitThreadEvent); ???Sleep(1000); ???//關(guān)閉Socket,釋放資源 ???int?err?=?closesocket(m_socket); ???if?(err?==?SOCKET_ERROR) ???{ ???return?FALSE; ???} ???return?TRUE; } /*----------------------------------------------------------------- 【函數(shù)介紹】:?向客戶端發(fā)送數(shù)據(jù) 【入口參數(shù)】:?buf:待發(fā)送的數(shù)據(jù) ??????????????len:待發(fā)送的數(shù)據(jù)長度 【出口參數(shù)】:?(無) 【返回??值】:?TRUE:發(fā)送數(shù)據(jù)成功;FALSE:發(fā)送數(shù)據(jù)失敗 ------------------------------------------------------------------*/ bool?CTCPCustom_CE::SendData(const?char?*?buf?,?int?len) { int?nBytes?=?0; int?nSendBytes=0; while?(nSendBytes?<?len) { ????nBytes?=?send(m_socket,buf+nSendBytes,len-nSendBytes,0); if?(nBytes==SOCKET_ERROR?) { int?iErrorCode?=?WSAGetLastError(); //觸發(fā)socket的Error事件 m_pTCPServer_CE->OnClientError(m_pTCPServer_CE->m_pOwnerWnd,this,iErrorCode); //觸發(fā)與服務(wù)器端斷開連接事件 m_pTCPServer_CE->OnClientClose(m_pTCPServer_CE->m_pOwnerWnd,this); //關(guān)閉socket Close(); return?FALSE; } nSendBytes?=?nSendBytes?+?nBytes; if?(nSendBytes?<?len) { ????Sleep(1000); } }? return?TRUE;? }
調(diào)用示例:
BOOL?CTCPServerDlg::OnInitDialog() { //m_bFullScreen?=?FALSE; CDialog::OnInitDialog(); //?Set?the?icon?for?this?dialog.??The?framework?does?this?automatically //??when?the?application's?main?window?is?not?a?dialog SetIcon(m_hIcon,?TRUE); //?Set?big?icon SetIcon(m_hIcon,?FALSE); //?Set?small?icon CenterWindow(GetDesktopWindow()); //?center?to?the?hpc?screen //?TODO:?Add?extra?initialization?here //?設(shè)置默認(rèn)值 m_localPort?=?5000; UpdateData(FALSE); return?TRUE;??//?return?TRUE??unless?you?set?the?focus?to?a?control } //?客戶端連接建立事件處理函數(shù) void?CALLBACK??CTCPServerDlg::OnClientConnect(CWnd*?pWnd,CTCPCustom_CE*?pTcpCustom) { CTCPServerDlg?*?pDlg?=?(CTCPServerDlg*)pWnd; CListBox?*?pLstConn?=?(CListBox*)pDlg->GetDlgItem(IDC_LSTCONN); ASSERT(pLstConn?!=?NULL); pLstConn->AddString(pTcpCustom->m_RemoteHost?+?_T("建立連接")); RETAILMSG(1,(TEXT("==OnClientConnect=%s?rn"),pTcpCustom->m_RemoteHost)); gTcpSendObj?=?*pTcpCustom; } //?客戶端SOCKET關(guān)閉事件處理函數(shù) void??CALLBACK?CTCPServerDlg::OnClientClose(CWnd*?pWnd,CTCPCustom_CE*?pTcpCustom) { CTCPServerDlg?*?pDlg?=?(CTCPServerDlg*)pWnd; int?iIndex?=?0; CListBox?*?pLstConn?=?(CListBox*)pDlg->GetDlgItem(IDC_LSTCONN); ASSERT(pLstConn?!=?NULL); iIndex?=?pLstConn->FindString(iIndex,pTcpCustom->m_RemoteHost?+?_T("建立連接")); if?(iIndex?==?LB_ERR) { return; } pLstConn->DeleteString(iIndex);? RETAILMSG(1,(TEXT("==OnClientClose=%s?rn"),pTcpCustom->m_RemoteHost)); } //?服務(wù)器端收到來自客戶端的數(shù)據(jù) void?CALLBACK?CTCPServerDlg::OnClientRead(CWnd*?pWnd,CTCPCustom_CE*?pTcpCustom,const?char?*buf,int?len) { ????CString?strRecv; CString?strLen; strLen.Format(L"%d",len); strRecv?=?buf; CTCPServerDlg?*?pDlg?=?(CTCPServerDlg*)pWnd; CListBox?*?pLstRecv?=?(CListBox*)pDlg->GetDlgItem(IDC_LSTRECV); ASSERT(pLstRecv?!=?NULL); pLstRecv->AddString(_T("************************************")); pLstRecv->AddString(_T("來自:?")?+?pTcpCustom->m_RemoteHost); pLstRecv->AddString(_T("數(shù)據(jù)長度:")+strLen); pLstRecv->AddString(strRecv); RETAILMSG(1,(TEXT("===%s?rn"),pTcpCustom->m_RemoteHost)); if?(!pTcpCustom->SendData("OK",strlen("OK"))) { AfxMessageBox(_T("發(fā)送失敗")); } } //客戶端Socket錯誤事件處理函數(shù) void?CALLBACK?CTCPServerDlg::OnClientError(CWnd*?pWnd,CTCPCustom_CE*?pTcpCustom,int?nErrorCode) { RETAILMSG(1,(TEXT("==OnClientError=%s?rn"),pTcpCustom->m_RemoteHost)); } //服務(wù)器端Socket錯誤事件處理函數(shù) void?CALLBACK?CTCPServerDlg::OnServerError(CWnd*?pWnd,CTCPServer_CE*?pTcpServer_CE,int?nErrorCode) { } //?監(jiān)聽按鈕單擊事件方法 void?CTCPServerDlg::OnBtnlisten()? { UpdateData(TRUE); //?設(shè)置?m_tcpServer?屬性 ??? m_tcpServer.m_LocalPort?=?m_localPort; m_tcpServer.m_pOwnerWnd?=?this; m_tcpServer.OnClientConnect?=?OnClientConnect; m_tcpServer.OnClientClose?=?OnClientClose; m_tcpServer.OnClientRead?=?OnClientRead; m_tcpServer.OnClientError?=?OnClientError; m_tcpServer.OnServerError?=?OnServerError; if?(m_tcpServer.Open()?EnableWindow(FALSE); CButton?*?pBtnClose?=?(CButton*)GetDlgItem(IDC_BTNCLOSE); ASSERT(pBtnClose?!=?NULL); pBtnClose->EnableWindow(TRUE); CButton?*pBtnSend?=?(CButton*)GetDlgItem(IDC_SendBtn); ASSERT(pBtnSend?!=?NULL); pBtnSend->EnableWindow(TRUE); } //關(guān)閉按鈕單擊事件代碼? void?CTCPServerDlg::OnBtnclose()? { if?(m_tcpServer.Close()?EnableWindow(TRUE); CButton?*?pBtnClose?=?(CButton*)GetDlgItem(IDC_BTNCLOSE); ASSERT(pBtnClose?!=?NULL); pBtnClose->EnableWindow(FALSE); CButton?*pBtnSend?=?(CButton*)GetDlgItem(IDC_SendBtn); ASSERT(pBtnSend?!=?NULL); pBtnSend->EnableWindow(FALSE); CListBox?*?pLstConn?=?(CListBox*)GetDlgItem(IDC_LSTCONN); ASSERT(pLstConn?!=?NULL); CListBox?*?pLstRecv?=?(CListBox*)GetDlgItem(IDC_LSTRECV); ASSERT(pLstRecv?!=?NULL); pLstConn->ResetContent(); pLstRecv->ResetContent(); } void?CTCPServerDlg::OnSendBtn()? { //?TODO:?Add?your?control?notification?handler?code?here if?(!gTcpSendObj.SendData("Send?data?ok(Server)",strlen("Send?data?ok(Server)"))) { AfxMessageBox(_T("發(fā)送失敗")); } }