利用CSocket實現進程間的通信


用CSocket類編寫網絡程序,既可以使用如CAsyncSocket類網絡程序一樣的Send和Receive函數來收發信息,也可以與CSocketFile類和CArchive類一起來管理對數據的發送和接收。
首先,了解CSocket連接的理論步驟:
1、在服務器端聲明一個用於監聽客戶端的CSocket對象,同時對應某個端口設定為監聽狀態;
2、在客戶端聲明CSocket對象,並通過IP和端口向服務器請求連接;
3、服務器端監聽到請求指令后,新建一個CSocket對象,用於與客戶端綁定,傳送和接收數據,服務器用於監聽的CSocket繼續監聽下一個客戶端的請求。
 
一、服務器端的建立
1.界面

控件屬性

 

控件類型 控件ID Caption屬性 控件變量 變量類型
列表框 IDC_LIST_SHOW m_ListShow CListBox
編輯框 IDC_EDIT_WRITE m_EditMsg CEdit
按鈕 IDC_BTN_SEND 發送 m_BtnSend CButton

2.定義CSocket類的派生類CServSocket和CRecvSocket。

從CSocket編程模型知道,服務器端需要兩種套接字,一個用來偵聽連接請求,一個用來與請求連接的套接字建立連接。因此,為程序添加兩個CSocket派生類:CServSocket和CRecvSocket,它們與對話框類密切配合,共同完成程序所要求實現的功能。

具體做法是:選擇"插入->類->MFC類",添加一個基於CSocket的子類CServSocket和CRecvSocket,點擊完成。其中,CServSocket類將用於監聽客戶端的連接請求,CRecvSocket用來與請求連接的套接字建立連接。

3.建立套接字與對話框類的關聯

在程序中,對話框類要用到套接字類,而套接字類在響應某些消息,如在函數OnAccept、OnReceive中進行處理時,也要改變對話框的某些控件狀態,以反映給用戶這些事情的發生。這里存在着兩個類相互使用的情況,把套接字類對象定義成對話框類的成員變量,同時在套接字類中也把對話框類定義為成員變量。

具體做法如下:

首先,在DlgTestDlg.h中加入套接字類頭文件的聲明,語句#pragma once的后面加入如下語句:

#include "ServSocket.h"

#include "RecvSocket.h"

然后在該文件中為CDlgTestDlg類增加兩個公有成員變量,語句如下:

CServSocket *m_pServSock;

CRecvSocket *m_pRecvSock;

這樣在對話框類中就可以使用套接字類了。

繼續在套接字類中加入對話框類信息。

首先,在ServSocket.h文件的開頭,語句#pragma once的后面加入如下語句:

class CDlgTestDlg;

然后,在該文件中為CServSocket類添加一個公有成員變量和一個構造函數:

CServSocket(CDlgTestDlg *pDlg);

CDlgTestDlg *m_pDlg;

接着在ServSocket.cpp文件中添加新的構造函數的實現,並添加一條關於DlgTestDlg.h文件的預編譯聲明,代碼如下:

#include "DlgTestDlg.h"

CServSocket::CServSocket(CDlgTestDlg *pDlg)
{
m_pDlg = pDlg;
}

這樣,在套接字類中也可以通過成員變量使用對話框了。

使用同樣的方法對CRecvSocket類進行設置,使其也可以通過成員變量使用對話框。

4.為套接字添加串行化讀寫信息的功能。
在服務器端的兩個套接字中,只有CRecvSocket套接字是真正與客戶端套接字建立連接,發送與接收數據的,因此,我們只為該類添加串行化讀寫信息功能。在RecvSocket.h文件中為類CRecvSocket添加三個 公有成員變量

CSocketFile *m_pFile;
CArchive *m_pArIn;
CArchive *m_pArOut;

5.在對話框中初始化套接字並偵聽連接請求。

在OnInitDialog函數中添加如下代碼:

// TODO: Add extra initialization here

if(m_pServSock = new CServSocket(this))
{
if(m_pServSock->Create (9547))
{
m_ListShow.InsertString(m_ListShow.GetCount(), "等待連接......");
m_pServSock->Listen ();
}
else
{
m_ListShow.InsertString(m_ListShow.GetCount(), "初始化失敗,請重新啟動程序!");
delete m_pServSock;
}
}
else
{
m_ListShow.InsertString(m_ListShow.GetCount(), "初始化失敗,請重新啟動程序!");
}

上述代碼主要是創建並初始化ServSock套接字,並開始偵聽連接請求。

6.接受連接請求。

由於是CServSocket類的ServSock對象在偵聽連接請求,因此由該類來接受連接請求。

首先,在ServSocket.h文件中加入如下語句:

#iinclude “RecvSocket.h”

然后,重載該類的OnAccept函數,在該函數中添加如下代碼:

CRecvSocket *tempSock;

if(tempSock = new CRecvSocket(this->m_pDlg))
{
if(Accept(*tempSock))
{
tempSock->m_pFile = new CSocketFile(tempSock);
tempSock->m_pArIn = new CArchive(tempSock->m_pFile ,CArchive::load );
tempSock->m_pArOut = new CArchive(tempSock->m_pFile ,CArchive::store );
m_pDlg->m_pRecvSock = tempSock;
tempSock=NULL;
m_pDlg->m_ListShow.InsertString(m_pDlg->m_ListShow.GetCount(), "連接成功,可以開始傳遞消息");
m_pDlg->m_BtnSend.EnableWindow (true);
}
else
{
m_pDlg->m_ListShow.InsertString(m_pDlg->m_ListShow.GetCount(), "客戶端當前的連接嘗試失敗");
delete tempSock;
}
}
else
{
m_pDlg->m_ListShow.InsertString(m_pDlg->m_ListShow.GetCount(), "連接套接字初始化失敗");
}

上述代碼首先調用Accept函數接受連接請求,然后為該連接創建一個CRecvSocket類型的套接字,並為該套接字關聯CArchive對象,使其能實現串行化傳輸信息的功能。最后把關聯好的套接字傳回給對話框對象供其使用。這樣,對話框對象的成員變量RecvSock套接字便與客戶端套接字之間建立了一條信息通道,信息將在兩個套接字之間傳遞。

7.接收信息。

連接建立成功后,當有信息到達服務器端時,就會引發RecvSock套接字對象的OnReceive函數,因此需要重載CRecvSocket類的OnReceive函數。添加代碼如下:

CString str;
(*m_pArIn)>>str;
str = "對方 : " + str;
m_pDlg->m_ListShow.InsertString(m_pDlg->m_ListShow.GetCount(), str);
m_pDlg->m_ListShow.SetCurSel(m_pDlg->m_ListShow.GetCount() - 1);

8.發送信息。

為對話框“發送”按鈕添加事件處理函數OnBtnSend(),代碼如下:

void CDlgTestDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
CString strText, str;

m_EditMsg.GetWindowText (strText);
if(strText.GetLength () == 0)
AfxMessageBox("空信息,所以不發出");
else
{
*(m_pRecvSock->m_pArOut)<<strText;
m_pRecvSock->m_pArOut->Flush();
strText = "你 : " + strText;
m_ListShow.InsertString(m_ListShow.GetCount(), strText);
m_ListShow.SetCurSel(m_ListShow.GetCount()-1);
m_EditMsg.SetWindowText("");
}
}

二、客戶端的建立

1.界面與控件屬性可參考服務器端。

2.創建套接字類(從CSocket類派生)。客戶端只需要一個套接字,命名為CClientSocket。

3.建立對話框類與套接字類的關聯。

首先,在DlgTestClientDlg.h文件的開頭,語句#pragma once后面加入如下語句:

#include “ClientSocket.h”

然后,在該文件中為CDlgTestClientDlg類添加一個公有成員變量,語句如下:

CClientSocket *m_pClientSock;

接着,在ClientSocket.h文件的開頭,語句#pragma once后面加入如下語句:

class CDlgTestClientDlg;

然后,在該文件中為CClientSocket類添加一公有成員變量和一個構造函數,語句如下:

CClientSocket(CDlgTestClientDlg *pDlg);

CDlgTestClientDlg *m_pDlg;

接着,在ClientSocket.cpp文件中添加新的構造函數的實現代碼,並添加一條關於DlgTestClientDlg.h文件的預編譯聲明,代碼如下:

#include "DlgTestClientDlg.h"

CClientSocket::CClientSocket(CDlgTestClientDlg *pDlg)
{
m_pDlg = pDlg;
}

這樣,便完成了對話框和套接字之間的連接了。

4.為套接字添加串行化讀寫信息的功能。

在ClientSocket.h文件中,為類CClientSocket添加三個公有成員變量,代碼如下:

CSocketFile *m_pFile;
CArchive *m_pArIn;
CArchive *m_pArOut;

5.在對話框中初始化套接字並建立連接。

在對話框類的OnInitDialog函數中添加如下代碼:

// TODO: Add extra initialization here
m_ListShow.InsertString(m_ListShow.GetCount(), "正在連接......");
if(m_pClientSock = new CClientSocket(this))
{
if(m_pClientSock->Create())
{
if(m_pClientSock->Connect ("localhost",9547))
{
m_pClientSock->m_pFile = new CSocketFile(m_pClientSock);
m_pClientSock->m_pArIn = new CArchive(m_pClientSock->m_pFile ,CArchive::load );
m_pClientSock->m_pArOut = new CArchive(m_pClientSock->m_pFile,CArchive::store );
m_ListShow.InsertString(m_ListShow.GetCount(), "連接成功,可以開始傳遞消息");
m_BtnSend.EnableWindow (true);
}
else
{
m_ListShow.InsertString(m_ListShow.GetCount(), "連接不成功");
delete m_pClientSock;
}
}
else
{
m_ListShow.InsertString(m_ListShow.GetCount(), "初始化失敗,請重新啟動程序");
delete m_pClientSock;
}
}
else
{
m_ListShow.InsertString(m_ListShow.GetCount(), "初始化失敗,請重新啟動程序");
}

6.接收消息。

消息到來時,會引發套接字的OnReceive消息,因此要重載CClientSocket類的OnReceive函數,在其中添加代碼如下:

CString str;

*m_pArIn>>str;  // 接收信息 Receive(str, str.GetLength()+1, 0);
str = "對方 : " + str;
m_pDlg->m_ListShow .InsertString(m_pDlg->m_ListShow.GetCount(), str);
m_pDlg->m_ListShow .SetCurSel(m_pDlg->m_ListShow .GetCount()-1);

7.發送信息。

為對話框“發送”按鈕添加事件處理函數OnBtnSend(),代碼如下:

void CDlgTestClientDlg::OnBtnSend()
{
// TODO: Add your control notification handler code here
CString str;

m_EditMsg.GetWindowText(str);
if(str.GetLength () == 0)
AfxMessageBox("空信息,所以不發出");
else
{
*(m_pClientSock->m_pArOut )<<str;
m_pClientSock->m_pArOut ->Flush();
str = "你 : " + str;
m_ListShow.InsertString(m_ListShow.GetCount(), str);
m_ListShow.SetCurSel(m_ListShow.GetCount()-1);
m_EditMsg.SetWindowText("");
}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM