MFC/Socket網路程式設計:[2]客戶端?

繼上一篇有關伺服器的網路程式設計,這裡繼續探討客戶端如何發出連線伺服器的請求,如何與伺服器進行資料傳輸,如何與其他客戶端交換資料,最後如何斷開與伺服器之間的連線。

關鍵技術就是TCP/IP協議,socket預設使用的是非阻塞式非同步傳輸通訊方式,對應MFC中的CSoket類,採用的是面向連線的TCP協議而不是UDP協議。

MFC/Socket網路程式設計:[2]客戶端

工具/原料

Visual Studio 2010/2013

方法/步驟

建立一個專案,與伺服器端類似,別忘了選擇“windows套接字”。建立好以後設計對話方塊介面。2個按鈕,1個用來連線或者斷開伺服器,另一個用來發送資料;2個編輯框,一個用來顯示接收到的資料,另一個用來輸入需要傳送的資料。

MFC/Socket網路程式設計:[2]客戶端

編輯控制元件的屬性,通過類嚮導新增相應的變數,雙擊按鈕新增按鈕按下處理事件。

MFC/Socket網路程式設計:[2]客戶端

新增客戶端類CClientSocket,通過類嚮導新增OnReceive函式。

MFC/Socket網路程式設計:[2]客戶端

修改客戶端類的標頭檔案:

/********************ClientSocket.h*********************/

#pragma once

class CClientSocket : public CSocket

{

public:

CClientSocket();

virtual ~CClientSocket();

virtual void OnReceive(int nErrorCode);

// 重寫接收函式,通過類嚮導生成

BOOL SendMSG(LPSTR lpBuff, int nlen);

// 傳送函式,用於傳送資料給伺服器

};

MFC/Socket網路程式設計:[2]客戶端

修改客戶端類的原始檔:

/********************ClientSocket.cpp*********************/

#include "stdafx.h"

#include "PhoneClient.h"

#include "ClientSocket.h"

#include "PhoneClientDlg.h"

CClientSocket::CClientSocket(){}

CClientSocket::~CClientSocket(){}

void CClientSocket::OnReceive(int nErrorCode)

{

// TODO: 在此新增專用程式碼和/或呼叫基類

char* pData = NULL;

pData = new char[1024];

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

UCHAR leng = 0;

CString str;

leng = Receive(pData, 1024, 0);

str = pData;

// 在編輯框中顯示接收到的資料

((CPhoneClientDlg*)theApp.GetMainWnd())->SetDlgItemTextW(IDC_DataReceive, str);

delete pData;

pData = NULL;

CSocket::OnReceive(nErrorCode);

}

BOOL CClientSocket::SendMSG(LPSTR lpBuff, int nlen)

{

//生成協議頭

if (Send(lpBuff, nlen) == SOCKET_ERROR)

{

AfxMessageBox(_T("傳送錯誤!"));

return FALSE;

}

return TRUE;

}

說明:當客戶端接收到伺服器端發的資料時會響應接收函式OnReceive,這裡只是簡單的將獲取的資訊顯示在編輯框中。SendMSG函式用於向伺服器傳送訊息,函式會在主對話方塊類中呼叫。

MFC/Socket網路程式設計:[2]客戶端

修改對話方塊類的標頭檔案,新增相關函式宣告以及必要的變數定義:

bool m_connect;

CClientSocket* pSock; // 客戶端套接字指標物件

BOOL WChar2MByte(LPCWSTR lpSrc, LPSTR lpDest, int nlen);

//字元轉換函式

public:

virtual BOOL PreTranslateMessage(MSG* pMsg);

//防止按下enter、esc時退出程式

MFC/Socket網路程式設計:[2]客戶端

在對話方塊類的原始檔中編寫所有宣告的函式,實現各項函式的功能。

1、 連線伺服器的按鈕事件處理函式

void CPhoneClientDlg::OnBnClickedConnect()

{

if (m_connect) // 如果已經連線,則斷開伺服器

{

m_connect = false;

pSock->Close();

delete pSock;

pSock = NULL;

m_ConPC.SetWindowTextW(_T("連線伺服器"));

UpdateData(false);

return;

}

else // 未連線,則連線伺服器

{

pSock = new CClientSocket();

if (!pSock->Create()) //建立套接字

{

AfxMessageBox(_T("建立套接字失敗!"));

return;

}

}

if (!pSock->Connect(_T("127.0.0.1"), port)) //連線伺服器

{

AfxMessageBox(_T("連線伺服器失敗!"));

return;

}

else

{

m_connect = true;

m_ConPC.SetWindowTextW(_T("斷開伺服器"));

UpdateData(false);

}

}

說明:本函式通過Create和Connect與伺服器建立連線。由於在本機上測試,所以IP為127.0.0.1,實際應用時可以新增一個控制元件用於輸入伺服器的IP。埠號必須與伺服器的一致,這裡的port是一個常量:

#define port 8000

MFC/Socket網路程式設計:[2]客戶端

2、 傳送按鈕的事件處理函式

void CPhoneClientDlg::OnBnClickedSend()

{

// TODO: 在此新增控制元件通知處理程式程式碼

if (!m_connect)return; //未連線伺服器則不執行

UpdateData(true); //獲取介面資料

if (m_DataSend != "")

{

char* pBuff = new char[m_DataSend.GetLength() * 2];

memset(pBuff, 0, m_DataSend.GetLength() * 2);

WChar2MByte(m_DataSend.GetBuffer(0), pBuff, m_DataSend.GetLength() * 2);

pSock->SendMSG(pBuff, m_DataSend.GetLength() * 2);

}

}

說明:這裡的SendMSG函式與伺服器端的不一致,函式實體在CClientSocket類中以實現。WChar2MByte字元轉換函式與伺服器端的一致,在這不再贅述。

MFC/Socket網路程式設計:[2]客戶端

對話方塊的主要函式就是以上2個,一個用於連線和斷開伺服器,另一個用於傳送資料。至於虛擬函式PreTeanslateMessage,其處理方法與伺服器中介紹的一致。將伺服器與客戶端都編寫好以後,就可以測試通訊效果,可以同時開啟多個客戶端,看看伺服器如何處理。

MFC/Socket網路程式設計:[2]客戶端

MFC/Socket網路程式設計:[2]客戶端

注意事項

這篇經驗需要參考上一篇關於伺服器端程式設計的經驗

伺服器端與客戶端通過socket實現網路通訊

資料, 網路, 客戶端, 伺服器, 協議,
相關問題答案