实验报告
学院(系)名称:计算机与通信工程学院
姓名
学号
专业
信息安全
班级
实验名称
实验3 基于windows的MFC windows编程
课程名称
网络编程
课程代码
0662146
实验时间
2016- 12 - 5
实验地点
7-219
批改意见
成绩
教师签字:               
1. 实验目的
VC++对原来的WindowsSockets库函数进行了一系列封装,继而产生CAsynSocket、CSocket、CSocketFile等类,它们封装着有关Socket的各种功能。利用VC6.0中MFC AppWizard和MFC ClassWizard功能将很容易实现网络聊天功能
2. 实验环境
搭载 Windows 7 操作系统的PC机
VC 6.0 编译器
3. 实验要求
编写基于windows的MFC windows的可进行socket通信的程序
4. 实验过程记录(源程序、测试用例、测试结果及心得体会等)
1.建立基于对话框的MFC 工程MySock
注意:基于对话框;支持window socket。
1.添加控件,并设置控件属性
控件类型
ID
Caption
Group Box
IDC_STATIC
socket类型
Radio Button
IDC_RCLIENT
客户端
RadioButton
IDC_RSERVER
服务器端
Static text
IDC_SNAME
服务器名
Edit box
IDC_ESERVERNAME
Static text
IDC_SPORT
端口号
Edit box
IDC_EPORT
Button
IDC_BCONNECT
连接
Button
IDC_BCLOSE
关闭
Static box
IDC_SMSG
消息
Edit box
IDC_EMSG
Static box
IDC_SSEND
发送
List box
IDC_LSEND
Static box
IDC_SRECV
接收
List box
IDC_LRECV
Button
IDC_BSEND
发送
3.为控件添加对应的成员变量和映射消息响应函数
双击“发送”按钮,添加OnBsend 函数;双击“关闭”按钮,添加OnBclose 函数;复用“连
接”按钮,当选择客户端按钮时显示“连接”;当选择服务端时显示“监听”。为两个单选按
钮添加一个消息函数, 根据当前选择的按钮修改命令的正文。具体做法是,双击
IDC_RCLIENT 控件,添加函数OnRType 函数,同时双击IDC_RSERVER 控件,添加该函
数。
编辑该函数,添加如下代码:
//in MySockDlg.cpp
void CMySockDlg::OnRType()
{
// TODO: Add your control notification handler code here
UpdateData(TRUE); //使控件与变量同步
if(m_iType==0) //m_iType=0 即client 端
m_ctlConnect.SetWindowText("连接");//m_ctlConnect 为控件“连接”按钮的映射变
else
m_ctlConnect.SetWindowText("监听");
}
运行程序,结果如下图所示:
选中“客户端”显示“连接”;选中“服务器端”显示“监听”:
4.添加CAsyncSocket 类的继承类MySocket
为了使应用程序能够捕捉和相应socket 事件,可以从AsyncSocket 创建自己的派生类。该类
需要有自己版本的事件函数,也需要一种把此事件传到对话框的方法。为把每个事件传给对
话框类、添加一个指向父对话框的指针作为socket 类的成员变量。对每个socket 事件使用
此指针调用事件函数。具体做法, 如图所示:
创建socket 类后,为该类添加一个私有成员变量m_pWnd 作为指向父对话框的指针;然后
必须在该类中,添加一个成员函数SetParent 以设置该指针,该函数在MySocket.cpp 文件中的
实现代码为:
void CMySocket::SetParent(CDialog* pWnd)
{
m_pWnd=pWnd;//设置成员指针变量
}
最后,MySocket 类,还必须添加事件函数,用于调用对话框类中名字相同的成员函数。为
添加OnAccept 事件函数,可以ClassWizard 窗口中,单击右键|add virtual function…
注意:同时添加#include "MySocket.h"
5.初始化CMySocket 类的成员函数
添加CMySocket 变量后,添加所有变量的初始化代码。默认设置为:应用程序类型设置为
客户端程序,服务器名为loopback,端口为4000,在两个CMySocket 对象中设置父对话框
的指针,指向对话框类对象。所有这些初始化,都在OnInitDialog 函数中完成。
注意:计算机名loopback 是TCP/IP 网络协议的一个特殊名字,表示你正在这台计算机上工
作,这个内部计算机名网址为127.0.0.1。需要与另一个程序连接,运行在同一台计算机上的
应用程序都用此名字和网址。
// in MySockDlg.cpp
BOOL CMySockDlg::OnInitDialog()
{
//省略代码(自动生成的)
// TODO: Add extra initialization here
//初始化控件对应的变量
m_iType = 0;
m_strName ="loopback";
m_iPort = 4000;
//更新控件
UpdateData(FALSE);
//设置Socket 对应的对话框
m_sConnectSocket.SetParent(this);
m_sListenSocket.SetParent(this);
return TRUE;
}
5.实现客户端与服务端间的连接功能
用户单击“连接”按钮后,就禁止了对话框上顶端的所有控件,此时,用户不可修改对方计
算机的设置或修改应用程序的监听方式。可以调用Create 函数,其Socket 变量根据应用程
序运行在客户机或服务器上而定。最后调用Connect 或Listen 函数初始化应用程序端的连接。
给应用程序添加如上功能,可以给“连接”按钮,ID 为IDC_BCONNECT,添加单击响应事
件函数,或者双击“连接”按钮,进入编辑代码。
//in MySockDlg.cpp
void CMySockDlg::OnBconnect()
{
// TODO: Add your control notification handler code here
//使变量与控件同步
UpdateData(TRUE);
//使连接和类型控件无效
GetDlgItem(IDC_BCONNECT)->EnableWindow(FALSE);
GetDlgItem(IDC_ESERVERNAME)->EnableWindow(FALSE);
GetDlgItem(IDC_EPORT)->EnableWindow(FALSE);
GetDlgItem(IDC_RCLIENT)->EnableWindow(FALSE);
GetDlgItem(IDC_RSERVER)->EnableWindow(FALSE);
//作为客户端还是服务器端?
if(m_iType == 0)
{
m_sConnectSocket.Create();//客户端,则创建缺省的Socket
m_sConnectSocket.Connect(m_strName,m_iPort);//打开与服务器的连接
}
else
{
m_sListenSocket.Create(m_iPort);//服务器端,则创建一个与制定端口号相关联的
socket
m_sListenSocket.Listen();//监听连接请求
}
}
为完成此连接,要为对话框类的OnAccept 和OnConnect 函数添加socket 事件函数。这些函
数都是Socket 类调用的,不需要任何参数,也不必返回任何结果。其中OnAccept 函数是在
对方应用程序试图连接正在监听的Socket 时调用,将调用Socket 对象的Accept 函数,传入
连接Sock 变量。当接受连接后,可以启用提示符和编辑框、输入和发送消息给对方应用程
序。实现把该函数添加给应用程序,应在对话类CMySockDlg 类添加一个共有访问成员函
数:(void)OnAccept,并编辑此函数,添加实现代码。
具体做法是,在classview 窗口中,CMySockDlg 类上单击右键,选择Add member function…
添加完成后,在MySockDlg.h 文件的类定义中,会出现OnAccept 函数的声明,同时
MySockDlg.cpp 文件中也会出现该函数相应的代码框架,只需直接在函数体中加入实现代码
即可。
//in MySockDlg.h
class CMySockDlg : public CDialog
{
public:
void OnAccept();
//省略代码
};
//in MySockDlg.cpp
void CMySockDlg::OnAccept()
{
//接受连接请求
m_sListenSocket.Accept(m_sConnectSocket);
//是文本和消息控件有效
GetDlgItem(IDC_EMSG)->EnableWindow( TRUE);
GetDlgItem(IDC_BSEND)->EnableWindow(TRUE);
GetDlgItem(IDC_SMSG)->EnableWindow(TRUE);
}
客户端,连接完成后只需使用消息输入和发送控件,还应使用close 按钮关闭客户机端的连
接。同样的方法给对话框类CMySockDlg 添加公有成员函数(void)OnConnect。
//in MySockDlg.cpp
void CMySockDlg::OnConnect()
{
//使文本和消息控件有效
GetDlgItem(IDC_EMSG)->EnableWindow( TRUE);
GetDlgItem(IDC_BSEND)->EnableWindow(TRUE);
GetDlgItem(IDC_SMSG)->EnableWindow(TRUE);
GetDlgItem(IDC_BCLOSE)->EnableWindow(TRUE);
}
此时,对话框类CMySockDlg 还缺少几个函数,按照上述方法,依次添加公有访问方式、
void 类型的函数OnSend、OnReceive、OnClose,这几个函数的具体实现代码后面添加。
到此,就可以编译和运行程序了。
编译后,同时可以启动两份拷贝,一份作为服务器端,单击“监听”按钮设置为监听模式;
另一个作为客户端,单击“连接”按钮与服务器连接。连接后,连接控件被禁用,消息发送
控件被启用。
7.实现客户端与服务器端间的消息收发功能
实现了应用程序的连接后,下面是实现消息的收发功能,即使用户能够在对话框的编辑框中
输入文本信息,然后单击“发送”按钮将消息发送给对方程序。发送后,正文添加到已发送
消息的列表中。实现上述功能,需要在单击“发送”按钮后,应用程序检查是否有发送的消
息,求取消息的长度,发送此消息,并把消息添加到已发送的列表框中。
把此项功能添加到应用程序,需要双击“发送”按钮,添加一个消息函数OnBsend,并为此
函数添加相关代码。我们让该函数调用对话框类的成员函数OnSend.
//in Mysockdlg.cpp
void CMySockDlg::OnSend()
{
int iLen;
int iSent;
//使控件与变量同步
UpdateData(TRUE);
//是否有信息要发送?
if(m_strMessage != "")
{
//获取消息的长度
iLen = m_strMessage.GetLength();
//发送消息
iSent = m_sConnectSocket.Send(LPCSTR(m_strMessage),iLen);
if(iSent == SOCKET_ERROR)//是否发送成功
{
//错误处理代码
}
else
{
//把消息添加到已发送列表中
m_ctlSend.AddString(m_strMessage);
//把控件与变量同步
UpdateData(FALSE);
}
}
}
void CMySockDlg::OnBsend()
{
OnSend();
}
OnReceive 事件被激发时表示消息已经到达,可使用Receive 函数从Socket 接收信息,接收
后将其转化成CString 类型的数据并把它添加到消息接收列表框中。对话框类的OnReceive
函数,实现此功能,过程类似于上述。
为CMySockDlg 类添加成员函数OnReceive(即上一节中已经添加过),并添加代码:
//in Mysockdlg.cpp
void CMySockDlg::OnReceive()
{
char *pBuf = new char[1025];
int iBufSize = 1024;
int iRcvd;
CString strRecv;
//接收消息
iRcvd = m_sConnectSocket.Receive(pBuf,iBufSize);
if(iRcvd == SOCKET_ERROR)
recv函数
{
//错误处理代码
}
else
{
pBuf[iRcvd] = NULL;//对信息进行结尾处理
strRecv = pBuf;//复制接收到的消息CString 类型的变量中
m_ctlRecv.AddString(strRecv);//增加信息到接收的列表框中
UpdateData(FALSE);//使变量与控件同步
}}
8.添加终止连接的代码
void CMySockDlg::OnClose()
{
m_sConnectSocket.Close();    //关闭连接
//使文本和控件无效
GetDlgItem(IDC_EMSG)->EnableWindow(FALSE);
GetDlgItem(IDC_BSEND)->EnableWindow(FALSE);
GetDlgItem(IDC_SMSG)->EnableWindow(FALSE);
GetDlgItem(IDC_BCLOSE)->EnableWindow(FALSE);
//清空发送和接收文本框
while (m_ctlSend.GetCount()!=0)
m_ctlSent.DeleteString(0);
while (m_ctlReceived.GetCount()!=0)
    m_ctlReceived.DeleteString(0);
if(m_iType == 0) //客户端?为下次连接做准备
{
//使连接和类型控件有效
GetDlgItem(IDC_BCONNECT)->EnableWindow(TRUE);
GetDlgItem(IDC_ESERVERNAME)->EnableWindow(TRUE);
GetDlgItem(IDC_EPORT)->EnableWindow(TRUE);
GetDlgItem(IDC_RCLIENT)->EnableWindow(TRUE);
GetDlgItem(IDC_RSERVER)->EnableWindow(TRUE);
}
}
实验截图:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。