日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器

 禁忌石 2017-05-20

MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
聽語(yǔ)音

  • |
  • 瀏覽:7267
  • |
  • 更新:

Windows程序開發(fā)中,如果涉及到網(wǎng)絡(luò)編程的話,一般少不了socket,socket作為應(yīng)用層與傳輸層之間的一個(gè)抽象層,可以理解為應(yīng)用程序與網(wǎng)絡(luò)協(xié)議之間的編程接口。

我曾通過MFC開發(fā)了一個(gè)簡(jiǎn)單C/S(客戶端/服務(wù)器)模式的應(yīng)用程序,主要是為了實(shí)現(xiàn)手機(jī)控制電腦,android網(wǎng)絡(luò)編程也可以通過socket實(shí)現(xiàn),這里以PC端編寫服務(wù)器程序和客戶端程序?yàn)槔f明socket編程的一般步驟。

MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器

工具/原料

  • Visual Studio 2010/2013

創(chuàng)建項(xiàng)目

  1. 1

    首先創(chuàng)建一個(gè)MFC項(xiàng)目,修改名稱以及存放路徑。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  2. 2

    項(xiàng)目配置,在向?qū)н^程中選擇“基于對(duì)話框”模式,并選擇“windows”套接字。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  3. 3

    設(shè)計(jì)服務(wù)器界面,控件有:4個(gè)靜態(tài)文本(Static Text),最后一個(gè)用于指示用戶連接個(gè)數(shù);一個(gè)按鈕(Button),用于打開或關(guān)閉服務(wù)器;2個(gè)編輯框(Edit Control),一個(gè)用于輸入端口號(hào),另一個(gè)只讀的用于顯示事件日志。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  4. 4

    修改各個(gè)控件的屬性,注意編輯框2還要把Multiline和Vertical Scroll屬性選為true,以實(shí)現(xiàn)多行顯示并自帶滾動(dòng)條。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  5. 5

    1、 給控件添加變量和事件處理函數(shù),這個(gè)通過類向?qū)Ь涂梢酝瓿?,變量如上表所示,事件只有“按鈕按下”一個(gè),雙擊按鈕自動(dòng)生成函數(shù),后面添加相關(guān)代碼即可。

    2、 在類視圖中添加一個(gè)新類CServerSocket,派生于CSocket類,對(duì)該類進(jìn)行類向?qū)砑尤齻€(gè)函數(shù):

    OnAccept()、OnClose()、OnReceive()

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
    END

編寫服務(wù)器類

  1. 1

    看看CServerSocket的類視圖,需要修改的有之前生成的三個(gè)函數(shù)。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  2. 2

    修改頭文件ServerSocket.h,定義主對(duì)話框的指針變量

    #pragma once

    #include "PhoneServerDlg.h"                              // 主對(duì)話框頭文件

    class CPhoneServerDlg;                                      //別忘了加上   

    class CServerSocket : public CSocket

    {

    public:

             CPhoneServerDlg* m_pDlg;                       // 主對(duì)話框指針對(duì)象

             CServerSocket();

             virtual ~CServerSocket();

             virtual void OnReceive(int nErrorCode);

             virtual void OnClose(int nErrorCode);

             virtual void OnAccept(int nErrorCode);

    };

  3. 3

    修改源文件ServerSocket.cpp,注意其中調(diào)用的函數(shù)都在主對(duì)話框類中定義。

    void CServerSocket::OnReceive(int nErrorCode)

    {

             m_pDlg->RecvData(this);                           // 接收數(shù)據(jù)

             CSocket::OnReceive(nErrorCode);

    }

    void CServerSocket::OnClose(int nErrorCode)

    {

             m_pDlg->RemoveClient(this);                   // 刪除下線用戶

             CSocket::OnClose(nErrorCode);

    }

    void CServerSocket::OnAccept(int nErrorCode)

    {

             m_pDlg->AddClient();                                  //添加上線用戶

             CSocket::OnAccept(nErrorCode);

    }

    至此,CServerSocket類的代碼就完成了,接下來編寫主類相關(guān)函數(shù)。

    END

編寫主對(duì)話框類

  1. 1

    修改頭文件PhoneServerDlg.h 

    1、   添加服務(wù)器類的頭文件。

    #include "ServerSocket.h"

    class CServerSocket;                  //一定要加上

    2、   添加函數(shù)聲明和變量定義

    CServerSocket* listenSocket;     // 用于打開服務(wù)器

    CPtrList m_clientList;                 // 鏈表用于存儲(chǔ)用戶

    bool m_connect;                       // 用于標(biāo)記服務(wù)器狀態(tài)

    void AddClient();                       // 增加用戶,響應(yīng)用戶請(qǐng)求

    void RemoveClient(CServerSocket* pSocket);          // 移除下線的用戶

    void RecvData(CServerSocket* pSocket);                 // 獲取數(shù)據(jù)

    void UpdateEvent(CString str);  // 更新事件日志

    BOOL WChar2MByte(LPCWSTR srcBuff, LPSTR destBuff, int nlen);        

    //字符轉(zhuǎn)換

    void SendMSG(CString str);       // 發(fā)送消息給各個(gè)客戶端

    void ControlPC(CString AndroidControl);  // 手機(jī)控制PC的響應(yīng)函數(shù)

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  2. 2

    修改PhoneServerDlg.cpp實(shí)現(xiàn)頭文件中聲明的函數(shù)

    1、 首先實(shí)現(xiàn)“打開服務(wù)器”按鈕的響應(yīng)函數(shù)

    void CPhoneServerDlg::OnBnClickedStartserver()

    {

             // TODO:  在此添加控件通知處理程序代碼

             if (m_connect)

             {

                       delete listenSocket;

                       listenSocket = NULL;

                       m_connect = false;

                       SetDlgItemText(IDC_StartServer, _T("打開服務(wù)器"));

                       UpdateEvent(_T("系統(tǒng)關(guān)閉服務(wù)器."));

                       return;

             }

             listenSocket = new CServerSocket();

             listenSocket->m_pDlg = this;

    // 指定對(duì)話框?yàn)橹鲗?duì)話框,不能少了這句

             UpdateData(true);

             if (!listenSocket->Create(m_port))                     

    // 創(chuàng)建服務(wù)器的套接字,IP地址默認(rèn)本機(jī)IP

             {

                       AfxMessageBox(_T("創(chuàng)建套接字錯(cuò)誤!"));

                       listenSocket->Close();

                       return;

             }

             if (!listenSocket->Listen())

             {

                       AfxMessageBox(_T("監(jiān)聽失?。?));

                       listenSocket->Close();

                       return;

             }

             m_connect = true;

             SetDlgItemText(IDC_StartServer, _T("關(guān)閉服務(wù)器"));

             UpdateEvent(_T("系統(tǒng)打開服務(wù)器."));

    }

    說明:本函數(shù)用于打開或關(guān)閉服務(wù)器,主要用到Create函數(shù)和Listen函數(shù)用于創(chuàng)建服務(wù)器和監(jiān)聽客戶端。其中端口號(hào)從編輯框獲取,應(yīng)用程序的可用端口范圍是1024-65535。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  3. 3

    2、 編寫AddClient函數(shù),用于增加用戶,響應(yīng)用戶請(qǐng)求

    void CPhoneServerDlg::AddClient()

    {

             CServerSocket *pSocket = new CServerSocket;

             pSocket->m_pDlg = this;

             listenSocket->Accept(*pSocket);

             pSocket->AsyncSelect(FD_READ | FD_WRITE | FD_CLOSE);

             m_clientList.AddTail(pSocket);

             m_userCount = m_clientList.GetCount();

             UpdateData(false);

             UpdateEvent(_T("用戶連接服務(wù)器."));

             SendMSG(_T("Hello!"));

    }

    說明:本函數(shù)在CServerSocket類中的OnAccept消息中調(diào)用,用于響應(yīng)用戶連接服務(wù)器的請(qǐng)求,主要函數(shù)為Accept,當(dāng)連接成功后,通過鏈表m_clientList保存新用戶,更新日志,向新用戶發(fā)送“Hello”表示歡迎。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  4. 4

    3、 編寫RemoveClient函數(shù),用于移除下線的用戶

    void CPhoneServerDlg::RemoveClient(CServerSocket* pSocket)

    {

             POSITION nPos = m_clientList.GetHeadPosition();

             POSITION nTmpPos = nPos;

             while (nPos)

             {

                       CServerSocket* pSockItem = (CServerSocket*)m_clientList.GetNext(nPos);

                       if (pSockItem->m_hSocket == pSocket->m_hSocket)

                       {                          

                                pSockItem->Close();

                                delete pSockItem;

                                m_clientList.RemoveAt(nTmpPos);

                                m_userCount = m_clientList.GetCount();

                                UpdateData(false);

                                UpdateEvent(_T("用戶離開."));

                                return;

                       }

                       nTmpPos = nPos;

             }

    }

    說明:本函數(shù)在CServerSocket類中的OnClose消息中調(diào)用,用到POSITION結(jié)構(gòu),查找存儲(chǔ)用戶中哪位用戶下線了,將下線用戶釋放,從鏈表中刪除,并更新日志。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  5. 5

    4、  編寫RecvData函數(shù),用于獲取數(shù)據(jù)

    void CPhoneServerDlg::RecvData(CServerSocket* pSocket)

    {

             char* pData = NULL;

             pData = new char[1024];

             memset(pData, 0, sizeof(char)* 1024);

             UCHAR leng = 0;

             CString str;

             if (pSocket->Receive(pData, 1024, 0) != SOCKET_ERROR)

             {

                       str = pData;

                       ControlPC(str);     // 依據(jù)指令控制電腦

                       SendMSG(str);     // 轉(zhuǎn)發(fā)數(shù)據(jù)給所有用戶,包括發(fā)送數(shù)據(jù)的用戶

             }

             delete pData;

             pData = NULL;

    }

    說明:本函數(shù)在CServerSocket類中的OnReceive消息中調(diào)用,用于處理接收到的數(shù)據(jù)并控制電腦,并將數(shù)據(jù)轉(zhuǎn)發(fā)給所有用戶(類似于群消息),通過CSocket類的GetPeerName函數(shù)可以獲取用戶的IP和端口號(hào)。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  6. 6

    5、  編寫UpdateEvent函數(shù),用于更新事件日志

    void CPhoneServerDlg::UpdateEvent(CString str)

    {

             CString string;

             CTime time = CTime::GetCurrentTime();                  

    // 獲取系統(tǒng)當(dāng)前時(shí)間

             str += _T("\r\n");                                                             

    // 用于換行顯示日志

             string = time.Format(_T("%Y/%m/%d %H:%M:%S  ")) + str;         

    // 格式化當(dāng)前時(shí)間

             int lastLine = m_event.LineIndex(m_event.GetLineCount() - 1);

    //獲取編輯框最后一行索引

             m_event.SetSel(lastLine+1,lastLine+2,0);                                     

    //選擇編輯框最后一行

             m_event.ReplaceSel(string);                                                             //替換所選那一行的內(nèi)容

    }

    說明:本函數(shù)在所有需要更新日志的地方都有調(diào)用,方便服務(wù)器記錄用戶的登錄和退出事件。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  7. 7

    6、  編寫WChar2MByte函數(shù),用于實(shí)現(xiàn)字符轉(zhuǎn)換

    BOOL CPhoneServerDlg::WChar2MByte(LPCWSTR srcBuff, LPSTR destBuff, int nlen)

    {

             int n = 0;

             n = WideCharToMultiByte(CP_OEMCP, 0, srcBuff, -1, destBuff, 0, 0, FALSE);

             if (n<nlen)return FALSE;

             WideCharToMultiByte(CP_OEMCP, 0, srcBuff, -1, destBuff, nlen, 0, FALSE);

             return TRUE;

    }

    說明:本函數(shù)在發(fā)送函數(shù)SendMSG中調(diào)用,用于字符集的轉(zhuǎn)換,將寬字符轉(zhuǎn)換為多字符集,不經(jīng)轉(zhuǎn)換的話,接收方只能接收一個(gè)字節(jié)。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  8. 8

    7、  編寫SendMSG函數(shù),用于發(fā)送消息給各個(gè)客戶端

    void CPhoneServerDlg::SendMSG(CString str)

    {

             char *pSend = new char[str.GetLength()];

             memset(pSend, 0, str.GetLength()*sizeof(char));

             if (!WChar2MByte(str.GetBuffer(0), pSend, str.GetLength()))

             {

                       AfxMessageBox(_T("字符轉(zhuǎn)換失敗"));

                       delete pSend;

                       return;

             }

             POSITION nPos = m_clientList.GetHeadPosition();

             while (nPos)

             {

                       CServerSocket* pTemp = (CServerSocket*)m_clientList.GetNext(nPos);

                       pTemp->Send(pSend, str.GetLength());

             }

             delete pSend;

    }

    說明:發(fā)送函數(shù),用于發(fā)送消息給所有用戶,主要函數(shù)為Send,在AddClient和RecvData中都有調(diào)用,可以隨時(shí)調(diào)用發(fā)消息給用戶。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  9. 9

    8、 編寫ControlPC函數(shù),用于處理接收到的指令并控制電腦,主要是為了實(shí)現(xiàn)手機(jī)控制而寫。

    void CPhoneServerDlg::ControlPC(CString AndroidControl)

    {

             if (AndroidControl == "mop")             //打開播放器

             {

             ShellExecute(NULL, _T("open"), _T("C:\\Program Files (x86)\\KuGou\\KGMusic\\KuGou.exe"), NULL, NULL, SW_SHOWNORMAL);

             }

             else if (AndroidControl == "mcl")         //關(guān)閉播放器

             {

                       DWORD id_num;

                       HWND hWnd = ::FindWindow(_T("kugou_ui"), NULL);

                       GetWindowThreadProcessId(hWnd, &id_num);                      

    //注意:第二個(gè)參數(shù)是進(jìn)程的ID,返回值是線程的ID。

                       HANDLE hd = OpenProcess(PROCESS_ALL_ACCESS, FALSE, id_num);

                       TerminateProcess(hd, 0);

             }

             else if (AndroidControl == "mpl" || AndroidControl == "mpa")                //播放/暫停

             {

                       keybd_event(VK_LMENU, 0, 0, 0);

                       keybd_event(VK_F5, 0, 0, 0);

                       keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, 0);

                       keybd_event(VK_LMENU, 0, KEYEVENTF_KEYUP, 0);

             }

    }

    說明:控制功能可以自己隨意添加,這里只以音樂播放為例進(jìn)行說明,ShellExecute函數(shù)用于調(diào)用其他應(yīng)用程序,關(guān)閉進(jìn)程比較麻煩一點(diǎn),這里先獲取應(yīng)用程序窗口的ID,通過OpenProcess和TerminateProcess終止進(jìn)程。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  10. 10

    9、 類向?qū)砑犹摵瘮?shù)PreTranslateMessage,并編寫代碼

    BOOL CPhoneServerDlg::PreTranslateMessage(MSG* pMsg)

    {

             switch (pMsg->wParam)

             {

             case VK_RETURN:

             case VK_ESCAPE:

                       return true; break;

             }

             return CDialogEx::PreTranslateMessage(pMsg);

    }

    說明:該函數(shù)用于防止按下enter或者esc時(shí)退出程序。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
  11. 11

    經(jīng)過以上步驟,服務(wù)器端的程序就完成了,雖然函數(shù)有點(diǎn)多,但只要理解了socket的使用流程并不難,總體可以概括為4步:

    1、創(chuàng)建服務(wù)器

    2、連接請(qǐng)求連接的客戶端

    3、與客戶端進(jìn)行數(shù)據(jù)傳輸(發(fā)送和接收)

    4、客戶端斷開服務(wù)器

    加上一些輔助代碼,可以更好的實(shí)現(xiàn)網(wǎng)絡(luò)通訊。客戶端的程序會(huì)在下一篇經(jīng)驗(yàn)中介紹。

    MFC/Socket網(wǎng)絡(luò)編程:[1]服務(wù)器
    END

注意事項(xiàng)

  • 注意類與類之間頭文件的引用
  • 如果不重寫虛函數(shù)PreTranslateMessage會(huì)導(dǎo)致按下回車或者esc時(shí)自動(dòng)退出程序
  • 合理設(shè)置端口號(hào),不要與其他程序發(fā)生沖突

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多