
控件属性
控件类型 | 控件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类进行设置,使其也可以通过成员变量使用对话框。
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("");
}
}