VC++-Socket网络通信编程_第1页
VC++-Socket网络通信编程_第2页
VC++-Socket网络通信编程_第3页
VC++-Socket网络通信编程_第4页
VC++-Socket网络通信编程_第5页
已阅读5页,还剩100页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第2章MFCSocket编程2.1

MFC及其Socket类2.2

C/S模式下网络程序的Socket通信实例2.3

与第三方程序的互通及Socket编程的本质2.1MFC及其Socket类2.1.1MFC简介MFC,微软根底类〔Microsoft

Foundation

Classes〕,同VCL类似,是一种应用框架〔ApplicationFramework〕,随微软VisualC++开发工具发布。MFC是很庞大的,如最新版本中包含了大约两百多个不同的类〔如图2.1所示〕。2.1.1MFC简介2.1.2MFC中的Socket类1.CAsyncSocket类CAsyncSocket类是从MFC的根类CObject派生出来的,它在较低的级别上封装WindowsSocketAPI。CAsyncSocket类在MFC套接字类中的继承位置如图2.2所示。CAsyncSocket类的成员函数如表2.1所示。2.1.2MFC中的Socket类2.CSocket类及其相关类〔1〕CSocket类。CSocket类是从CAsyncSocket派生而来的,它继承了CAsyncSocket对WindowsSocketAPI的封装。〔2〕CSocket与CArchive、CSocketFile类的配合使用。用CSocket类编写网络程序,既可以使用如CAsyncSocket类网络程序一样的Send和Receive函数来收发信息,也可以与CSocketFile类和CArchive类一起来管理对数据的发送和接收。

2.2C/S模式下网络程序的Socket通信实例2.2.1客户—效劳器方式〔C/S模式〕1.网络软件的通用体系结构客户〔Client〕和效劳器〔Server〕是指通信中所涉及的两个应用进程。客户—效劳器方式所描述的是进程之间效劳和被效劳的关系。在图2.3中,主机A运行客户程序而主机B运行效劳器程序。2.2.1客户—效劳器方式〔C/S模式〕2.最简单的Socket通信流程一个只有客户方向效劳方发信息的单向通信,并且也只有客户方会主动提出断开连接的最简单的情形〔相反过程的原理是一样的〕,其双方Socket之间的关系如图2.4所示。2.2.1客户—效劳器方式〔C/S模式〕由上面这个十分简单的过程很容易得出最简单的Socket通信流程,如图2.5所示。2.2.2CAsyncSocket类编程根底1.对象分析由节分析的最简单的Socket通信流程可见,要实现这样一个完整流程需要三个套接字对象:客户端一个〔我们称为“客户Socket”〕,效劳器端两个〔一个用于监听,称为“监听Socket”;另一个用于接收客户发来的信息,称为“效劳Socket”〕,这三个套接字对象对应三个Socket类,都继承自CAsyncSocket,分别给它们取名如表2.2所示。Socket对象类名客户SocketCClientSocket监听SocketCListenSocket服务SocketCServerSocket2.2.2CAsyncSocket类编程根底2.创立工程和套接字对象首先创立客户端工程。翻开VisualStudio2008环境,建立一个新的基于对话框的MFC工程,工程名称为ChatClient,接着一直单击“下一步”按钮,直到设置程序“高级功能”对话框,如图2.6所示。2.2.2CAsyncSocket类编程根底创立类名为CClientSocket的客户Socket对象,下面给工程添加类,选择菜单命令“工程”→“添加类”,如图2.7所示。2.2.2CAsyncSocket类编程根底在弹出的“添加类”对话框中选择“MFC类”项,单击“添加”按钮〔如图2.8所示〕。2.2.2CAsyncSocket类编程根底在“MFC类向导”对话框中输入类名CClientSocket,向导将自动为这个添加的类生成名为“ClientSocket.h”和“ClientSocket.cpp”的头文件和源文件,如图2.9所示。2.2.2CAsyncSocket类编程根底单击“完成”按钮,可以在类视图中看到刚刚添加的类CClientSocket〔如图2.10所示〕。2.2.2CAsyncSocket类编程根底3.理清程序文件的组织结构〔1〕客户端程序文件。翻开已经创立好的客户端工程,在解决方案资源管理器中可以看到工程的所有程序文件〔如图2.11所示〕。2.2.2CAsyncSocket类编程根底全部程序文件可以分成三类:第一类是.h后缀的头文件,用来集中声明定义程序中用到的类、变量、函数、宏等;第二类是.cpp后缀的源文件,这是程序代码的主体,集中存放程序的源代码;第三类是资源文件,存放程序中用到的资源,如图标、图像、音频、视频等,2.2.2CAsyncSocket类编程根底〔2〕效劳器端的源文件。同理,效劳器端也对应这几种程序文件,翻开效劳器工程,可以看到它们〔如图2.12所示〕。2.2.2CAsyncSocket类编程根底4.用头文件和类对象将程序源文件联成有机整体例如,已经创立了各个Socket对象并且也有了它们各自对应的程序文件,但这些文件仍然是孤立的,相互之间的代码无法访问,要使它们能联系在一起,使控制程序的主文件能够自如地操纵Socket,就必须通过头文件声明和创立类对象成员变量将各个类联成有机的整体。要使客户端程序能够创立和控制本地的Socket,在客户端工程界面控制模块的头文件ChatClientDlg.h中添加如下两行代码:#include"ClientSocket.h" //使主界面程序能够访问Socket类的代码文件CClientSocketm_ClientSocket;//为了后面与效劳器通信而定义的Socket成员变量2.2.2CAsyncSocket类编程根底以上两行代码的添加位置如图2.13所示中“//ADD”记号之间标出的局部。2.2.2CAsyncSocket类编程根底反过来要使Socket能够访问到主界面上的控件,以便能够将自己的状况随时反映给主程序并在主界面上显示出来,也需要在Socket源文件ClientSocket.cpp中添加头文件声明:#include"ChatClientDlg.h"同理,要使效劳端程序能够创立和控制本地的Socket,也要在效劳端工程界面控制模块的头文件ChatServerDlg.h中添加如下代码:#include"ListenSocket.h" //使主界面程序能够访问监听Socket类的代码文件#include"ServerSocket.h" //使主界面程序能够访问效劳Socket类的代码文件CServerSocketm_ServerSocket; //为了后面与客户通信而定义的Socket成员变量CListenSocketm_ListenSocket; //为了监听客户端的连接请求而定义的Socket成员变量2.2.2CAsyncSocket类编程根底以上四行代码的添加位置如图2.14所示中“//ADD”记号之间标出的局部。2.2.2CAsyncSocket类编程根底5.布局简洁的界面在客户端“资源视图”展开的目录树下双击Dialog文件夹下第二个工程,转到用户界面设计工作区〔如图2.15所示〕。2.2.2CAsyncSocket类编程根底完成的客户端简化界面〔如图2.16所示〕上,包括IP地址控件、列表框各1个,文本框两个,四个按钮。2.2.2CAsyncSocket类编程根底用相同的方法设置效劳器端的用户界面如图2.17所示,也一样为IP地址控件关联变量ServerIP,为文本框控件关联int型变量sPort,为列表框关联变量m_ListWords。2.2.2CAsyncSocket类编程根底6.雏形程序试运行到此为止,这个程序的雏形已经形成,分别运行客户和效劳器端的工程如图2.18所示。2.2.2CAsyncSocket类编程根底7.程序代码的组织接下来就要为这个程序雏形注入灵性,添加核心源代码了。在此之前,先来回忆一下前面设计的那个最简单的Socket通信流程,如图2.19所示。2.2.2CAsyncSocket类编程根底从上面已经标注了所用函数的通信流程图,可以进一步得出下面的源程序代码组织框图〔如图2.20所示〕。2.2.2CAsyncSocket类编程根底8.源代码完全剖析〔1〕客户端源码。客户端用户首先主动发起连接,以下是“连接”按钮的事件过程,位于ChatClientDlg.cpp文件中://连接效劳器BYTEnFild[4];CStringsIP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);m_ClientSocket.Create(); //创立客户端Socketm_ClientSocket.Connect(sIP,sPort); //发起连接请求2.2.2CAsyncSocket类编程根底Create()函数用来创立和初始化套接字,具体过程为:构造套接字对象m_ClientSocket后,调用Create()成员函数创立Socket句柄,并调用Bind()成员函数将其与指定的地址绑定,Create()函数原型为:BOOLCreate(UINTnSocketport=0,intnSocketType=SOCK_STREAM,longlEvent=FD_READ︱FD_WRITE︱FD_OOB︱FD_ACCEPT︱FD_CONNECT︱FD_CLOSE,LPCTSTRlpszSocketaddress=NULL);Connect()函数用于未连接的数据流或者数据报套接字建立连接。其函数原型为:BOOLConnect(LPCTSTRlpszHostAddress,UINTnHostPort);BOOLConnect(constSOCKADDR*lpSockAddr,intnSockAddrLen);2.2.2CAsyncSocket类编程根底客户端也可以随时主动断开通信连接,下面是“断开”按钮的事件过程://断开与效劳器的连接m_ClientSocket.Close(); //关闭客户端Socketm_ListWords.AddString("从效劳器断开");Close()函数用来关闭套接字并释放Socket描述符,其函数原型为:virtualvoidClose();客户端可以向效劳器发送信息,“发送”按钮的事件过程为://向效劳器发信息UpdateData();m_ClientSocket.Send(m_sWords,m_sWords.GetLength()); //发信息m_ListWords.AddString("发送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);Send()函数通过数据报或者数据流向对方套接字发送数据,其函数原型为:virtualintSend(constvoid*lpBuf,intnBufLen,intnFlags=0);2.2.2CAsyncSocket类编程根底在类视图中选中CClientSocket,在界面右下角的属性窗口中单击“重写”按钮,就可以为该Socket类编写被动响应网络事件的函数〔如图2.21所示〕。2.2.2CAsyncSocket类编程根底选择OnConnect()函数,为其添加代码,系统将该函数的代码自动置于ClientSocket.cpp文件中。OnConnect()函数代码如下://确认客户端是否成功连接到效劳器if(nErrorCode){ AfxMessageBox("连接失败,请您重试!"); return;}((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("连接效劳器成功!");((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);2.2.2CAsyncSocket类编程根底〔2〕效劳器端源码〔ChatServerDlg.cpp文件中〕。“开始监听”按钮的事件过程如下://监听开始,效劳器等待连接请求的到来BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket.Create(sPort,1,FD_ACCEPT,sIP); //创立效劳端监听Socketm_ListenSocket.Listen(1); //开始监听m_ListWords.AddString("监听开始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.AddString("等待客户端连接……");Listen()函数用于侦听连接请求,原型为:BOOLListen(intnConnectionBackloh=5);2.2.2CAsyncSocket类编程根底Accept()函数接受一个套接字的连接请求,从连接请求队列中取出第一个连接,创立一个与这个套接字具有相同属性的套接字,并与参数rConnectedSocket相关联,原始的套接字依然保持翻开并且侦听状态。函数原型为:virtualBOOLAccept(CAsyncSocket&rConnectedSocket,SOCKADDR*lpSockAddr=NULL,int*lpSockAddrlen=NULL);2.2.2CAsyncSocket类编程根底表2.3列出了套接字可以侦测到的网络事件类型。事件标记事件FD_READ接收读准备好的通知FD_WRITE接收写准备好的通知FD_OOB接收带外数据到达的通知FD_ACCEPT接收等待连接成功的通知FD_CONNECT接收已连接好的通知FD_CLOSE接收套接字关闭的通知2.2.2CAsyncSocket类编程根底OnReceive()函数代码〔ServerSocket.cpp文件中〕:

//接收客户端发来的信息charszTemp[200];intn=Receive(szTemp,200); //接收信息szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString(sTemp);//显示信息((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex( ((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);OnClose()代码://关闭与客户端的通信信道((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("客户端断开连接");((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(((CChatServerDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);Close(); //关闭与客户端通信的Socket2.2.2CAsyncSocket类编程根底9.运行结果现在这个程序已经具备了最简单的单向通信功能,客户端发出信息效劳器端可以收到,运行结果如图2.22所示。2.2.2CAsyncSocket类编程根底10.从单向通信到双向交流下面就来添加效劳端到客户端的通信功能。先在效劳器界面上添加一个编辑信息的文本框和一个发送按钮,如图2.23所示。2.2.2CAsyncSocket类编程根底效劳器的“发送”按钮添加与客户端的一样的事件过程。“发送”按钮的事件过程代码〔在ChatServerDlg.cpp中〕如下:UpdateData();m_ServerSocket.Send(m_sWords,m_sWords.GetLength());m_ListWords.AddString("发送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);是为客户端添加OnReceive方法,代码置于ClientSocket.cpp中。OnReceive()函数代码如下:charszTemp[200];intn=Receive(szTemp,200);szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString(sTemp);((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex( ((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);

2.2.2CAsyncSocket类编程根底参照客户端断开连接的原理,在效劳器界面上安放一个“断开”按钮〔如图2.24所示〕。2.2.2CAsyncSocket类编程根底为这个“断开”按钮编写与客户端“断开”按钮一样的事件过程代码:m_ServerSocket.Close();m_ListWords.AddString("与客户端断开");下来就是一样的原理,在客户端添加响应网络事件的函数代码,为客户端Socket重写网络事件响应函数OnClose,代码自动置于ClientSocket.cpp中:((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.AddString("效劳器端断开了");((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.SetTopIndex(((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->m_ListWords.GetCount()-1);Close();2.2.2CAsyncSocket类编程根底运行后界面如图2.25所示。2.2.2CAsyncSocket类编程根底11.程序界面的优化和控制先在界面上添加一些控件并重新设计布局如图2.26和图2.27所示。2.2.2CAsyncSocket类编程根底各控件关联的变量见表2.4和表2.5。控件变量(包括类型)IP地址控件contrlServerIP“端口”编辑框contrlServerPort;intsPort“连接”按钮contrlm_ButtonConnect“断开”按钮contrlm_ButtonDisconnect列表框contrlm_ListWords“清空”按钮contrlm_ButtonClear发送信息编辑框contrlm_EditWords;CStringm_sWords“发送”按钮contrlm_ButtonSend“退出”按钮contrlm_ButtonExit控件变量(包括类型)IP地址控件contrlServerIP“端口”编辑框contrlServerPort;intsPort列表框contrlm_ListWords“断开”按钮contrlm_ButtonDisconnect“清空”按钮contrlm_ButtonClear“退出”按钮contrlm_ButtonExit“开始监听”按钮contrlm_ButtonListen“停止监听”按钮contrlm_ButtonStopListen发送信息编辑框contrlm_EditWords;CStringm_sWords“发送”按钮contrlm_ButtonSend2.2.2CAsyncSocket类编程根底截取上面的一小段代码来举一个例子让读者对使用EnableWindow函数控制界面的方法有个感性认识。例如:“开始监听”事件过程代码如下:(1) ServerIP.EnableWindow(false); //使IP地址控件不可用(2) ServerPort.EnableWindow(false); //使端口号固定无法修改(3) m_ButtonListen.EnableWindow(false); //使监听按钮失效(4) m_ButtonStopListen.EnableWindow(); //使用户可以随时停止监听(5) m_ButtonClear.EnableWindow(); //使清空按钮生效(6) m_ButtonExit.EnableWindow(false); //使退出按钮失效2.2.2CAsyncSocket类编程根底效劳器端程序在用户按下“开始监听”按钮前后界面的变化比照方图2.28所示。

2.2.2CAsyncSocket类编程根底“关于”事件过程代码如下: CAboutDlgdlgAbout; dlgAbout.DoModal(); //显示“关于”对话框在资源视图的目录树Dialog子目录下的第一个工程IDD_ABOUTBOX就是“关于”对话框的ID,双击它可以进入“关于”对话框的设计界面〔如图2.29所示〕。2.2.2CAsyncSocket类编程根底在此,用户可以设计“关于”对话框的外观,写上版权声明。在这个例子中,简单地设计双方通信软件的“关于”对话框如图2.30所示。2.2.2CAsyncSocket类编程根底12.程序完全演示分别开启客户端程序和效劳器端程序〔如图2.31所示〕。2.2.2CAsyncSocket类编程根底在效劳器端输入IP地址和端口,单击“开始监听”按钮,效劳器于是在这个地址上等待客户来连接,历史记录栏里将自动记下这一事件,如图2.32所示。2.2.2CAsyncSocket类编程根底在客户端地址栏里输入和效劳器一样的IP和端口,单击“连接”按钮,连上效劳器,可以看到双方的状态栏里都反映了这次连接的情况〔如图2.33所示〕。2.2.2CAsyncSocket类编程根底接下来双方就可以互相通信了,可以互发信息,信息内容会实时自动地显示在双方的通信记录列表中,并且你还会发现:当某方的通信记录多到一定量时,列表框会自动以滚动条方式显示〔如图2.34所示〕。2.2.2CAsyncSocket类编程根底通信过程中任何一方都可以主动断开连接〔如图2.35所示〕。2.2.2CAsyncSocket类编程根底也可以重新连接,并随时清空通信记录〔如图2.36所示〕。2.2.2CAsyncSocket类编程根底单击“关于”按钮,查看版权信息〔如图2.37所示〕。2.2.2CAsyncSocket类编程根底效劳器随时可以停止监听,客户端连接效劳器失败时会弹出失败提示〔如图2.38所示〕。2.2.3CAsyncSocket类程序的指针实现1.传统程序机制的弊端归纳起来节的程序存在以下一些编程机制上的弊端:〔1〕Socket的创立、使用和销毁不够灵活,无法支持很多Socket动态参与通信过程的情况。〔2〕程序代码分散在各个不同的Socket模块中,不利于统一管理和维护。〔3〕如果在Socket的代码中要访问和控制主对话框界面上的控件,那么需要运用AfxGetApp()全局函数获取主窗口CWinApp类指针的方法,这意味着每一个在Socket中访问到主对话框界面上控件的语句前都要写上冗长的类似下面的这句代码:((CChatClientDlg*)(AfxGetApp()->m_pMainWnd))->2.2.3CAsyncSocket类程序的指针实现2.用对话框指针机制实现的Socket程序〔1〕创立工程、添加类、用户界面。创立完成后在客户和效劳器端工程中各添加一个基于CAsyncSocket类的MySocket类,它是用来给通信双方动态生成Socket对象使用的,如图2.39所示。2.2.3CAsyncSocket类程序的指针实现参照上节例子程序给这个程序设计个一模一样的界面,如图2.40所示。2.2.3CAsyncSocket类程序的指针实现〔2〕用对话框指针机制组织新的程序雏形。客户端。代码添加位置如图2.41所示。2.2.3CAsyncSocket类程序的指针实现给MySocket类添加网络事件处理函数,在这里我们添加OnClose()、OnConnect()、OnReceive()三个函数,分别用于响应效劳器断开连接事件、客户发起连接请求事件、接收到效劳器发来的数据,系统将自动为每个函数生成函数声明和函数体的框架,如图2.42所示。2.2.3CAsyncSocket类程序的指针实现在ChatClientDlg.cpp中将MySocket类对象指针初始化为空,并写出我们上面已声明的三个函数OnClose()、OnConnect()、OnReceive()的函数体,为它们的实现代码预留出空间〔如图2.43所示〕,同时实现SocketReset()函数,代码如下:voidCChatClientDlg::SocketReset() //SocketReset函数实现{ if(m_ClientSocket!=NULL) { deletem_ClientSocket; m_ClientSocket=NULL; }}2.2.3CAsyncSocket类程序的指针实现2.2.3CAsyncSocket类程序的指针实现效劳端。采用与客户端类似的方法,在MySocket.h中添加: classCChatServerDlg; //先对主对话框类进行前导声明 CChatServerDlg*m_dlg; //定义主对话框指针 voidGetDlg(CChatServerDlg*dlg); //指针获取函数与客户端一样,系统自动为每个函数生成函数声明和函数体框架,另外我们在ChatServerDlg.cpp中将MySocket类对象指针初始化为空。#include"MySocket.h"//引用MySocket类头文件,为了后面定义动态Socket对象指针MySocket*m_ServerSocket;//MySocket类对象指针,用于动态生成与客户通信的 //SocketMySocket*m_ListenSocket;//定义MySocket类对象指针,用于动态生成监听SocketvoidOnReceive();voidOnClose();voidOnAccept(); //要在主对话框代码中实现的效劳器端功能的三个函数voidSocketReset(); //重置销毁不再使用的套接字2.2.3CAsyncSocket类程序的指针实现在ChatServerDlg.cpp中写出OnAccept()、OnClose()、OnReceive()三个函数的函数体,为它们的实现代码预留出空间,同时实现SocketReset函数,代码如下:voidCChatServerDlg::SocketReset() //SocketReset函数实现{ if(m_ServerSocket!=NULL) { deletem_ServerSocket; //在此要销毁两个Socket,一个是与客户通

//信的Socket m_ServerSocket=NULL; } if(m_ListenSocket!=NULL) { deletem_ListenSocket; //还有一个是监听Socket m_ListenSocket=NULL; }}2.2.3CAsyncSocket类程序的指针实现试运行的界面如图2.44所示。2.2.3CAsyncSocket类程序的指针实现〔3〕代码的复制、修改。客户端。“连接”按钮事件过程代码如下://初始化套接字,获取对话框指针if(!AfxSocketInit()){ MessageBox("WindowSocketinitialfailed!","Receive",MB_ICONSTOP); return;}m_ClientSocket=newMySocket;m_ClientSocket->GetDlg(this);//连接效劳器BYTEnFild[4];CStringsIP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);m_ClientSocket->Create(); //创立客户端Socketm_ClientSocket->Connect(sIP,sPort); //发起连接请求2.2.3CAsyncSocket类程序的指针实现“断开”按钮事件过程代码如下://断开与效劳器的连接m_ClientSocket->Close(); //关闭客户端SocketSocketReset(); //防止指针悬空m_ListWords.AddString("从效劳器断开");“发送”按钮事件过程代码如下:UpdateData();m_ClientSocket->Send(m_sWords,m_sWords.GetLength());//向效劳器发送信息m_ListWords.AddString("发送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket类程序的指针实现OnClose()函数代码如下:m_ListWords.AddString("效劳器端断开了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);m_ClientSocket->Close();SocketReset(); //防止指针悬空OnReceive()函数代码如下:charszTemp[200];intn=m_ClientSocket->Receive(szTemp,200);szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);m_ListWords.AddString(sTemp);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);OnConnect()函数代码如下:m_ListWords.AddString("连接效劳器成功!");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket类程序的指针实现效劳器端。“开始监听”按钮事件过程代码如下://初始化套接字,获取对话框指针if(!AfxSocketInit()){ MessageBox("WindowSocketinitialfailed!","Send",MB_ICONSTOP); return;}m_ListenSocket=newMySocket;m_ListenSocket->GetDlg(this);//监听开始,效劳器等待连接请求的到来BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket->Create(sPort,1,FD_ACCEPT,sIP); //创立效劳端监听Socketm_ListenSocket->Listen(1); //开始监听m_ListWords.AddString("监听开始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.AddString("等待客户端连接……");2.2.3CAsyncSocket类程序的指针实现“停止监听”按钮事件过程代码如下://停止监听m_ListenSocket->Close(); //关闭效劳端监听Socketif(m_ListenSocket!=NULL) //防止指针悬空{ deletem_ListenSocket; m_ListenSocket=NULL;}m_ListWords.AddString("停止监听");“断开”按钮的事件过程代码如下:m_ServerSocket->Close();if(m_ServerSocket!=NULL){ deletem_ServerSocket; m_ServerSocket=NULL;}m_ListWords.AddString("与客户端断开");2.2.3CAsyncSocket类程序的指针实现“发送”按钮的事件过程代码如下:UpdateData();m_ServerSocket->Send(m_sWords,m_sWords.GetLength());//获取文本长度m_ListWords.AddString("发送:"+m_sWords); //显示发送文件长度m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);OnAccept()函数代码如下://动态创立用于通信的Socketm_ServerSocket=newMySocket;m_ServerSocket->GetDlg(this);//接受客户端的连接请求m_ListenSocket->Accept(*m_ServerSocket); //接受连接请求m_ServerSocket->AsyncSelect(FD_READ|FD_CLOSE);m_ListWords.AddString("接受了一个客户端的连接请求");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket类程序的指针实现OnClose()函数代码如下://关闭与客户端的通信信道m_ListWords.AddString("客户端断开连接");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);m_ServerSocket->Close(); //关闭与客户端通信的Socketif(m_ServerSocket!=NULL){ deletem_ServerSocket; m_ServerSocket=NULL;}OnReceive()函数代码如下://接收客户端发来的信息charszTemp[200];intn=m_ServerSocket->Receive(szTemp,200); //接收信息szTemp[n]='\0';CStringsTemp;sTemp.Format("收到:%s",szTemp);m_ListWords.AddString(sTemp); //显示信息m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.3CAsyncSocket类程序的指针实现“退出”按钮的事件过程代码如下:voidCChatServerDlg::OnBnClickedCancel(){ //TODO:在此添加控件通知处理程序代码

SocketReset(); OnCancel();}2.2.3CAsyncSocket类程序的指针实现〔4〕运行比照。来运行一下这个程序,同时运行一下节的传统机制程序,并将它们放在一个桌面上比照方图2.45所示。2.2.3CAsyncSocket类程序的指针实现3.对话框指针机制的好处使用对话框指针机制的程序比传统程序更有显著的优越性,主要表达在以下三个方面:〔1〕更加灵活。〔2〕代码更集中、更有条理。〔3〕程序语句更加简洁。2.2.4CSocket类编程1.创立工程、添加类、用户界面分别创立客户端和效劳器端工程,设置和前两节的程序完全一样,创立完成后分别在客户和效劳器端工程中各添加一个基于CSocket类的MySocket类〔如图2.46所示〕。2.2.4CSocket类编程再对照前两节实例程序的界面给这个程序设计一个一模一样的界面,如图2.47所示。2.2.4CSocket类编程2.程序雏形架构

客户端。在MySocket.h中添加如下代码:#include"Afxsock.h" //引用Afxsock.h头文件,目的是使用CSocket类classCChatClientDlg; //为了能在MySocket类中定义主对话框类指针,先对主对话框类进行

//前导声明CChatClientDlg*m_dlg; //定义主对话框指针voidGetDlg(CChatClientDlg*dlg); //获取主对话框指针的函数在ChatClientDlg.h中添加如下代码:#include"MySocket.h"//引用MySocket类的头文件,是为了下面定义一个

//MySocket类对象指针MySocket*m_ClientSocket; //客户端套接字指针CArchive*m_archiveIn; //收到的信息的存储文件CArchive*m_archiveOut; //发送的信息的存储文件CSocketFile*m_socketfile; //用于发送和接收数据的缓冲区voidOnReceive();voidOnClose();voidSocketReset();2.2.4CSocket类编程定义变量m_Input〔如图2.48所示〕,用于后面接收对方发来的数据:CStringm_Input;在ChatClientDlg.cpp中添加初始化代码:m_ClientSocket=NULL;m_archiveIn=NULL;m_archiveOut=NULL;m_socketfile=NULL;2.2.4CSocket类编程在ChatClientDlg.cpp中写出我们上面声明的函数OnClose和OnReceive的函数体,为它们的实现代码预留出空间,同时实现SocketReset()函数,其代码。在MySocket.cpp中实现获取主对话框指针的GetDlg()函数,并通过指针引用主对话框程序代码中的网络事件处理函数:#include"ChatClientDlg.h"voidMySocket::GetDlg(CChatClientDlg*dlg)//获得窗口界面的指针{ m_dlg=dlg;}voidMySocket::OnClose(intnErrorCode){ //TODO:在此添加专用代码和/或调用基类

m_dlg->OnClose(); CSocket::OnClose(nErrorCode);}voidMySocket::OnReceive(intnErrorCode){ //TODO:在此添加专用代码和/或调用基类

m_dlg->OnReceive(); AsyncSelect(FD_CLOSE|FD_READ|FD_WRITE); CSocket::OnReceive(nErrorCode);}2.2.4CSocket类编程效劳端。采用与客户端类似的方法,在MySocket.h中添加如下代码:#include"Afxsock.h"classCChatServerDlg;CChatServerDlg*m_dlg;voidGetDlg(CChatServerDlg*dlg);在ChatServerDlg.h中添加如下代码:#include"MySocket.h"MySocket*m_ServerSocket; //MySocket类对象指针,用于动态生成与客户通信的SocketMySocket*m_ListenSocket; //定义MySocket类对象指针,用于动态生成监听SocketCArchive*m_archiveIn;CArchive*m_archiveOut;CSocketFile*m_socketfile;voidOnReceive();voidOnClose();voidOnAccept();voidSocketReset();2.2.4CSocket类编程在ChatServerDlg.cpp中添加如下初始化代码:m_ServerSocket=NULL;m_ListenSocket=NULL;m_archiveIn=NULL;m_archiveOut=NULL;m_socketfile=NULL;在ChatServerDlg.cpp中写出OnAccept()、OnClose()、OnReceive()三个函数的函数体,为它们的实现代码预留出空间,同时实现SocketReset函数,其代码。在MySocket.cpp中实现获取主对话框指针的GetDlg()函数,并通过指针引用主对话框的三个函数,其代码。2.2.4CSocket类编程3.代码解析客户端。“连接”按钮的事件过程代码。“断开”按钮事件过程代码如下:SocketReset();m_ListWords.AddString("从效劳器断开");“发送”按钮事件过程代码如下:UpdateData();*m_archiveOut<<m_sWords;m_archiveOut->Flush();m_ListWords.AddString("发送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket类编程OnClose()函数代码如下:m_ListWords.AddString("效劳器端断开了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);SocketReset();OnReceive()函数代码如下:*m_archiveIn>>m_Input;m_archiveIn->Flush();m_ListWords.AddString("收到:"+m_Input);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket类编程“断开”按钮事件过程代码如下:SocketReset();m_ListWords.AddString("从效劳器断开");“发送”按钮事件过程代码如下:UpdateData();*m_archiveOut<<m_sWords;m_archiveOut->Flush();m_ListWords.AddString("发送:"+m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket类编程OnClose()函数代码如下:m_ListWords.AddString("效劳器端断开了");m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);SocketReset();OnReceive()函数代码如下:*m_archiveIn>>m_Input;m_archiveIn->Flush();m_ListWords.AddString("收到:"+m_Input);m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);2.2.4CSocket类编程效劳端。“开始监听”按钮事件过程如下:if(!AfxSocketInit()) //初始化套接字{ MessageBox("WindowSocketinitialfailed!","Send",MB_ICONSTOP); return;}m_ListenSocket=newMySocket;m_ListenSocket->GetDlg(this);BYTEnFild[4];CStringsIP,sP;UpdateData();ServerIP.GetAddress(nFild[0],nFild[1],nFild[2],nFild[3]);sIP.Format("%d.%d.%d.%d",nFild[0],nFild[1],nFild[2],nFild[3]);sP.Format("%d",sPort);m_ListenSocket->Create(sPort,1,sIP); //创立效劳端监听Socketm_ListenSocket->Listen(1); //开始监听m_ListWords.AddString("监听开始:");m_ListWords.AddString("地址"+sIP+"端口"+sP);m_ListWords.Ad

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论