版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、2.12.1 MFCMFC及其SocketSocket类2.22.2 C/SC/S模式下网络程序的SocketSocket通信实例2.32.3 与第三方程序的互通及Socket编程的本质2.1.1 MFC2.1.1 MFC简介简介MFCMFC,微软基础类(MicrosoftFoundationClasses),同VCL类似,是一种应用框架(Application Framework),随微软Visual C+ 开发工具发布。MFC是很庞大的,如最新版本中包含了大约两百多个不同的类(如图2.1所示)。1. CAsyncSocket1. CAsyncSocket类类CAsyncSocket类是从M
2、FC的根类CObject派生出来的,它在较低的级别上封装Windows Socket API。CAsyncSocket类在MFC套接字类中的继承位置如图2.2所示。CAsyncSocket类的成员函数如表2.1所示。2 2CSocketCSocket类及其相关类类及其相关类(1)CSocketCSocket类。类。CSocket类是从CAsyncSocket派生而来的,它继承了CAsyncSocket对Windows Socket API的封装。(2)CSocketCSocket与与CArchiveCArchive、CSocketFileCSocketFile类的配合使用。类的配合使用。用CS
3、ocket类编写网络程序,既可以使用如CAsyncSocket类网络程序一样的Send和Receive函数来收发信息,也可以与CSocketFile类和CArchive类一起来管理对数据的发送和接收。2.2.1 2.2.1 客户客户服务器方式(服务器方式(C/SC/S模式)模式)1 1网络软件的通用体系结构网络软件的通用体系结构客户(Client)和服务器(Server)是指通信中所涉及的两个应用进程。客户服务器方式所描述的是进程之间服务和被服务的关系。在图2.3中,主机A运行客户程序而主机B运行服务器程序。2 2最简单的最简单的SocketSocket通信流程通信流程一个只有客户方向服务方发
4、信息的单向通信,并且也只有客户方会主动提出断开连接的最简单的情形(相反过程的原理是一样的),其双方Socket之间的关系如图2.4所示。由上面这个十分简单的过程很容易得出最简单的Socket通信流程,如图2.5所示。1 1对象分析对象分析由2.2.1节分析的最简单的Socket通信流程可见,要实现这样一个完整流程需要三个套接字对象:客户端一个(我们称为“客户Socket”),服务器端两个(一个用于监听,称为“监听Socket”;另一个用于接收客户发来的信息,称为“服务Socket”),这三个套接字对象对应三个Socket类,都继承自CAsyncSocket,分别给它们取名如表2.2所示。Soc
5、ket对象类 名客户SocketCClientSocket监听SocketCListenSocket服务SocketCServerSocket2 2创建工程和套接字对象创建工程和套接字对象首先创建客户端工程。打开Visual Studio 2008环境,建立一个新的基于对话框的MFC项目,项目名称为ChatClient,接着一直单击“下一步”按钮,直到设置程序“高级功能”对话框,如图2.6所示。创建类名为CClientSocket的客户Socket对象,下面给工程添加类,选择菜单命令“项目”“添加类”,如图2.7所示。在弹出的“添加类”对话框中选择“MFC类”项,单击“添加”按钮(如图2.8所
6、示)。在“MFC类向导”对话框中输入类名CClientSocket,向导将自动为这个添加的类生成名为“ClientSocket.h”和“ClientSocket.cpp”的头文件和源文件,如图2.9所示。单击“完成”按钮,可以在类视图中看到刚刚添加的类CClientSocket(如图2.10所示)。3 3理清程序文件的组织结构理清程序文件的组织结构(1)客户端程序文件。打开已经创建好的客户端工程,在解决方案资源管理器中可以看到工程的所有程序文件(如图2.11所示)。全部程序文件可以分成三类:l第一类是.h后缀的头文件,用来集中声明定义程序中用到的类、变量、函数、宏等;l第二类是.cpp后缀的源
7、文件,这是程序代码的主体,集中存放程序的源代码;l第三类是资源文件,存放程序中用到的资源,如图标、图像、音频、视频等,(2)服务器端的源文件。同理,服务器端也对应这几种程序文件,打开服务器工程,可以看到它们(如图2.12所示)。4 4用头文件和类对象将程序源文件联成有机整体用头文件和类对象将程序源文件联成有机整体例如,已经创建了各个Socket对象并且也有了它们各自对应的程序文件,但这些文件仍然是孤立的,相互之间的代码无法访问,要使它们能联系在一起,使控制程序的主文件能够自如地操纵Socket,就必须通过头文件声明头文件声明和创建类对象成员创建类对象成员变量变量将各个类联成有机的整体。要使客户
8、端程序能够创建和控制本地的Socket,在客户端工程界面控制模块的头文件ChatClientDlg.h中添加如下两行代码:#include ClientSocket.h /使主界面程序能够访问Socket类的代码文件CClientSocket m_ClientSocket;/为了后面与服务器通信而定义的Socket成员变量以上两行代码的添加位置如图2.13所示中“/ADD”记号之间标出的部分。反过来要使Socket能够访问到主界面上的控件,以便能够将自己的状况随时反映给主程序并在主界面上显示出来,也需要在Socket源文件ClientSocket.cpp中添加头文件声明:#include Ch
9、atClientDlg.h同理,要使服务端程序能够创建和控制本地的Socket,也要在服务端工程界面控制模块的头文件ChatServerDlg.h中添加如下代码:#include ListenSocket.h /使主界面程序能够访问监听Socket类的代码文件#include ServerSocket.h /使主界面程序能够访问服务Socket类的代码文件CServerSocket m_ServerSocket;/为了后面与客户通信而定义的Socket成员变量CListenSocket m_ListenSocket;/为了监听客户端的连接请求而定义的Socket成员变量同样,在ListenSo
10、cket.cpp和ServerSocket.cpp中添加/ADD#include ChatServerDlg.h/ADD以上四行代码的添加位置如图2.14所示中“/ADD”记号之间标出的部分。5 5布局简洁的界面布局简洁的界面在客户端“资源视图”展开的目录树下双击Dialog文件夹下第二个项目,转到用户界面设计工作区(如图2.15所示)。完成的客户端简化界面(如图2.16所示)上,包括IP地址控件、列表框各1个,文本框两个,四个按钮。用相同的方法设置服务器端的用户界面如图2.17所示,也一样为IP地址控件关联变量ServerIP,为文本框控件关联int型变量sPort,为列表框关联变量m_Li
11、stWords。6 6雏形程序试运行雏形程序试运行到此为止,这个程序的雏形已经形成,分别运行客户和服务器端的工程如图2.18所示。各控件关联的变量见表2.4和表2.5。7 7程序代码的组织程序代码的组织接下来就要为这个程序雏形注入灵性,添加核心源代码了。在此之前,先来回顾一下前面设计的那个最简单的Socket通信流程,如图2.19所示。从上面已经标注了所用函数的通信流程图,可以进一步得出下面的源程序代码组织框图(如图2.20所示)。CClientSocket类中添加lvirtual void OnConnect(int nErrorCode);lvirtual void OnReceive(i
12、nt nErrorCode);lvirtual void OnClose(int nErrorCode);在类视图中选中CClientSocket,在界面右下角的属性窗口中单击“重写”按钮,就可以为该Socket类编写被动响应网络事件的函数(如图2.21所示)。选择OnConnect()函数,为其添加代码,系统将该函数的代码自动置于ClientSocket.cpp文件中。OnConnect()函数代码如下:/确认客户端是否成功连接到服务器if(if(nErrorCodenErrorCode) ) AfxMessageBox(连接失败,请您重试!);return;return; (CChatCl
13、ientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(连接服务器成功!);(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()- 1);选择OnReceive ()函数,为其添加代码,系统将该函数的代码自动置于ClientSocket.cpp文件中。OnReceive()函数代码如下:/ADDchar szTemp200;int n=
14、Receive(szTemp,200);szTempn=0;CString sTemp;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);/ADD选择OnClose ()函数,为其添
15、加代码,系统将该函数的代码自动置于ClientSocket.cpp文件中。OnClose()函数代码如下:/ADD(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(服务器端断开了);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);Close();8 8源代码完全剖析源代码完全剖析(1)客户端源码。
16、客户端用户首先主动发起连接,以下是“连接”按钮的事件过程,位于ChatClientDlg.cpp文件中:/连接服务器BYTE nFild4;CString sIP;UpdateData();ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,nFild2,nFild3);m_ClientSocket.Createm_ClientSocket.Create();();/创建客户端Socketm_ClientSocket.Connectm_ClientSocket.Connect
17、( (sIP,sPortsIP,sPort); );/发起连接请求Create()函数用来创建和初始化套接字,具体过程为:构造套接字对象m_ClientSocket后,调用Create()成员函数创建Socket句柄,并调用Bind()成员函数将其与指定的地址绑定,Create()函数原型为:BOOL Create(UINT nSocketport = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ FD_WRITEFD_OOBFD_ACCEPTFD_CONNECTFD_CLOSE,LPCTSTR lpszSocketaddres
18、s = NULL);Connect()函数用于未连接的数据流或者数据报套接字建立连接。其函数原型为:BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort);BOOL Connect(const SOCKADDR*lpSockAddr, int nSockAddrLen);客户端也可以随时主动断开通信连接,下面是“断开”按钮的事件过程:/断开与服务器的连接m_ClientSocket.Closem_ClientSocket.Close();();/关闭客户端Socketm_ListWords.AddString(从服务器断开);Close()函
19、数用来关闭套接字并释放Socket描述符,其函数原型为:virtual void Close();客户端可以向服务器发送信息,“发送”按钮的事件过程为:/向服务器发信息UpdateData();m_ClientSocket.Sendm_ClientSocket.Send( (m_sWords,m_sWords.GetLengthm_sWords,m_sWords.GetLength();();/发信息m_ListWords.AddString(发送: + m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);Send()函数
20、通过数据报或者数据流向对方套接字发送数据,其函数原型为:virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);清空按钮代码:/ADDm_ListWords.ResetContent();/ADDCListenSocket类中添加virtual void OnAccept(int nErrorCode);/ADD/ 接受客户端的连接请求Accept(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ServerSocket);/接受连接请求(CChatServerDlg *)(Afx
21、GetApp()-m_pMainWnd)-m_ServerSocket.AsyncSelect(FD_READ|FD_CLOSE);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(接受了一个客户端的连接请求);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);/ADDCServerSocket类中
22、添加virtual void OnReceive(int nErrorCode);:/ADD/接收客户端发来的信息char szTemp200;int n=Receive(szTemp,200);/接收信息szTempn=0; CString sTemp;sTemp.Format(收到:%s,szTemp);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(sTemp);/显示信息(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(C
23、ChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);CServerSocket类中添加virtual void OnClose(int nErrorCode); :/ADD/关闭与客户端的通信信道(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(客户端断开连接);(CChatServerDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex(CChatServerDlg *)(Af
24、xGetApp()-m_pMainWnd)-m_ListWords.GetCount()-1);Close();/关闭与客户端通信的Socket/ADD(2)服务器端源码(ChatServerDlg.cpp文件中)。“开始监听”按钮的事件过程如下:/监听开始,服务器等待连接请求的到来BYTE nFild4;CString sIP,sP;UpdateData();ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,nFild2,nFild3);sP.Format(%d,sPor
25、t);m_ListenSocket.Createm_ListenSocket.Create(sPort,1,FD_ACCEPT,sIP);(sPort,1,FD_ACCEPT,sIP);/创建服务端监听Socketm_ListenSocket.Listenm_ListenSocket.Listen(1);(1);/开始监听m_ListWords.AddString(监听开始:);m_ListWords.AddString(地址 + sIP + 端口 + sP);m_ListWords.AddString(等待客户端连接);Listen()函数用于侦听连接请求,原型为:BOOL Listen(i
26、nt nConnectionBackloh = 5);(2)服务器端源码(ChatServerDlg.cpp文件中)。“停止监听”按钮的事件过程如下:/ADD/停止监听m_ListenSocket.Close();/关闭服务端监听Socketm_ListWords.AddString(停止监听);(2)服务器端源码(ChatServerDlg.cpp文件中)。“发送”按钮的事件过程如下:/ADD UpdateData(); m_ServerSocket.Send(m_sWords,m_sWords.GetLength();/获取文本长度 m_ListWords.AddString(发送:+m_
27、sWords);/显示发送文件长度记录 m_ListWords.SetTopIndex(m_ListWords.GetCount()-1);/ADD(2)服务器端源码(ChatServerDlg.cpp文件中)。“断开”按钮的事件过程如下:/ADDm_ServerSocket.Close();m_ListWords.AddString(与客户端断开);(2)服务器端源码(ChatServerDlg.cpp文件中)。“清空”按钮的事件过程如下:/ADDm_ListWords.ResetContent();/ADDAccept()函数接受一个套接字的连接请求,从连接请求队列中取出第一个连接,创建一
28、个与这个套接字具有相同属性的套接字,并与参数rConnectedSocket相关联,原始的套接字依然保持打开并且侦听状态。函数原型为:virtual BOOL Accept(CAsyncSocket& rConnectedSocket, SOCKADDR *lpSockAddr = NULL,int* lpSockAddrlen = NULL);表2.3列出了套接字可以侦测到的网络事件类型。事 件 标 记事 件FD_READ接收读准备好的通知FD_WRITE接收写准备好的通知FD_OOB接收带外数据到达的通知FD_ACCEPT接收等待连接成功的通知FD_CONNECT接收已连接好的通知FD_C
29、LOSE接收套接字关闭的通知9 9运行结果运行结果现在这个程序已经具备了最简单的单向通信功能,客户端发出信息服务器端可以收到,运行结果如图2.22所示。1010从单向通信到双向交流从单向通信到双向交流下面就来添加服务端到客户端的通信功能。先在服务器界面上添加一个编辑信息的文本框和一个发送按钮,如图2.23所示。服务器的“发送”按钮添加与客户端的一样的事件过程。“发送”按钮的事件过程代码(在ChatServerDlg.cpp中)如下:UpdateData();m_ServerSocket.Sendm_ServerSocket.Send( (m_sWords,m_sWords.GetLengthm
30、_sWords,m_sWords.GetLength();();m_ListWords.AddString(发送: + m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);是为客户端添加OnReceive方法,代码置于ClientSocket.cpp中。OnReceive()函数代码如下:char szTemp200;intint n = Receive(szTemp,200); n = Receive(szTemp,200);szTempn = 0;CString sTemp;sTemp.Format(收到:%s,szT
31、emp);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.AddString(sTemp);(CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.SetTopIndex( (CChatClientDlg *)(AfxGetApp()-m_pMainWnd)-m_ListWords.GetCount() - 1);参照客户端断开连接的原理,在服务器界面上安放一个“断开”按钮(如图2.24所示)。为这个“断开”按钮编写与客户端“断开”按钮一样的事件过程代码:m_ServerSock
32、et.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_pMainW
33、nd)-m_ListWords.GetCount()-1);Close();Close();运行后界面如图2.25所示。1111程序界面的优化和控制程序界面的优化和控制先在界面上添加一些控件并重新设计布局如图2.26和图2.27所示。各控件关联的变量见表2.4和表2.5。控 件变量(包括类型)IP地址控件contrl ServerIP“端口”编辑框contrl ServerPort;int sPort“连接”按钮contrl m_ButtonConnect“断开”按钮contrl m_ButtonDisconnect列表框contrl m_ListWords“清空”按钮contrl m_But
34、tonClear发送信息编辑框contrl m_EditWords;CString m_sWords“发送”按钮contrl m_ButtonSend“退出”按钮contrl m_ButtonExit控 件变量(包括类型)IP地址控件contrl ServerIP“端口”编辑框contrl ServerPort;int sPort列表框contrl m_ListWords“断开”按钮contrl m_ButtonDisconnect“清空”按钮contrl m_ButtonClear“退出”按钮contrl m_ButtonExit“开始监听”按钮contrl m_ButtonListen“停
35、止监听”按钮contrl m_ButtonStopListen发送信息编辑框contrl m_EditWords;CString m_sWords“发送”按钮contrl m_ButtonSend截取上面的一小段代码来举一个例子让读者对使用EnableWindow函数控制界面的方法有个感性认识。例如:“开始监听”事件过程代码如下:(1)ServerIP.EnableWindow(false);/使IP地址控件不可用(2)ServerPort.EnableWindow(false);/使端口号固定无法修改(3)m_ButtonListen.EnableWindow(false);/使监听按钮失效
36、(4)m_ButtonStopListen.EnableWindow();/使用户可以随时停止监听(5)m_ButtonClear.EnableWindow();/使清空按钮生效(6)m_ButtonExit.EnableWindow(false);/使退出按钮失效服务器端程序在用户按下“开始监听”按钮前后界面的变化对比如图2.28所示。 “关于”事件过程代码如下:CAboutDlg dlgAbout;dlgAbout.DoModal();/显示“关于”对话框在资源视图的目录树Dialog子目录下的第一个项目IDD_ABOUTBOX就是“关于”对话框的ID,双击它可以进入“关于”对话框的设计界
37、面(如图2.29所示)。在此,用户可以设计“关于”对话框的外观,写上版权声明。在这个例子中,简单地设计双方通信软件的“关于”对话框如图2.30所示。1212程序完全演示程序完全演示分别开启客户端程序和服务器端程序(如图2.31所示)。在服务器端输入IP地址和端口,单击“开始监听”按钮,服务器于是在这个地址上等待客户来连接,历史记录栏里将自动记下这一事件,如图2.32所示。在客户端地址栏里输入和服务器一样的IP和端口,单击“连接”按钮,连上服务器,可以看到双方的状态栏里都反映了这次连接的情况(如图2.33所示)。接下来双方就可以互相通信了,可以互发信息,信息内容会实时自动地显示在双方的通信记录列
38、表中,并且你还会发现:当某方的通信记录多到一定量时,列表框会自动以滚动条方式显示(如图2.34所示)。通信过程中任何一方都可以主动断开连接(如图2.35所示)。也可以重新连接,并随时清空通信记录(如图2.36所示)。单击“关于”按钮,查看版权信息(如图2.37所示)。服务器随时可以停止监听,客户端连接服务器失败时会弹出失败提示(如图2.38所示)。1 1传统程序机制的弊端传统程序机制的弊端归纳起来2.2.2节的程序存在以下一些编程机制上的弊端:(1)Socket的创建、使用和销毁不够灵活,无法支持很多Socket动态参与通信过程的情况。(2)程序代码分散在各个不同的Socket模块中,不利于统
39、一管理和维护。(3)如果在Socket的代码中要访问和控制主对话框界面上的控件,则需要运用AfxGetApp()全局函数获取主窗口CWinApp类指针的方法,这意味着每一个在Socket中访问到主对话框界面上控件的语句前都要写上冗长的类似下面的这句代码:(CChatClientDlg*)(AfxGetApp()-m_pMainWnd)-2 2用对话框指针机制实现的用对话框指针机制实现的SocketSocket程序程序(1)创建工程、添加类、用户界面。创建完成后在客户和服务器端工程中各添加一个基于CAsyncSocket类的MySocket类,它是用来给通信双方动态生成Socket对象使用的,如
40、图2.39所示。参照上节例子程序给这个程序设计个一模一样的界面,如图2.40所示。(2)用对话框指针机制组织新的程序雏形。l客户端。代码添加位置如图2.41所示。给MySocket类添加网络事件处理函数,在这里我们添加OnClose()、OnConnect()、OnReceive()三个函数,分别用于响应服务器断开连接事件、客户发起连接请求事件、接收到服务器发来的数据,系统将自动为每个函数生成函数声明和函数体的框架,如图2.42所示。lvoid MySocket:GetDlg(CChatClientDlg * dlg) /获得窗口界面的指针llm_dlg=dlg;ll/ADDlvoid MyS
41、ocket:OnClose(int nErrorCode)ll/ TODO: 在此添加专用代码和/或调用基类l/ADDlm_dlg-OnClose();l/ADDlCAsyncSocket:OnClose(nErrorCode);llvoid MySocket:OnConnect(int nErrorCode)ll/ TODO: 在此添加专用代码和/或调用基类l/ADDl/确认客户端是否成功连接到服务器lif(nErrorCode)llAfxMessageBox(连接失败,请您重试!);lreturn;ll m_dlg-OnConnect();l/ADDlCAsyncSocket:OnConn
42、ect(nErrorCode);llvoid MySocket:OnReceive(int nErrorCode)ll/ TODO: 在此添加专用代码和/或调用基类l/ADDlm_dlg-OnReceive();l/ADDlCAsyncSocket:OnReceive(nErrorCode);ll在MySocket.cpp上面加上l/ADDl#include ChatClientDlg.hl/ADD在ChatClientDlg.cpp中将MySocket类对象指针初始化为空,并写出我们上面已声明的三个函数OnClose()、OnConnect()、OnReceive()的函数体,为它们的实现代
43、码预留出空间(如图2.43所示),同时实现SocketReset()函数,代码如下:void CChatClientDlg:SocketReset()/SocketReset函数实现if(m_ClientSocket!=NULL) delete m_ClientSocket;m_ClientSocket=NULL; l/ADDlvoid CChatClientDlg:SocketReset()llif(m_ClientSocket!=NULL)lldelete m_ClientSocket;lm_ClientSocket=NULL;lllvoid CChatClientDlg:OnClose(
44、)llm_ListWords.AddString(服务器端断开了);lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);lm_ClientSocket-Close();lSocketReset();/避免指针悬空llvoid CChatClientDlg:OnReceive()llchar szTemp200;lint n=m_ClientSocket-Receive(szTemp,200);lszTempn=0;lCString sTemp;lsTemp.Format(收到:%s,szTemp);lm_ListWords.AddString(
45、sTemp);lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);llvoid CChatClientDlg:OnConnect()llm_ListWords.AddString(连接服务器成功!);lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);ll/ADDl服务端。采用与客户端类似的方法,在MySocket.h中添加:class CChatServerDlg;/先对主对话框类进行前导声明CChatServerDlg * m_dlg;/定义主对话框指针void GetDlg(CChatSe
46、rverDlg * dlg); /指针获取函数与客户端一样,系统自动为每个函数生成函数声明和函数体框架,另外我们在ChatServerDlg.cpp中将MySocket类对象指针初始化为空。#include MySocket.h /引用MySocket类头文件,为了后面定义动态Socket对象指针MySocket * m_ServerSocket; /MySocket类对象指针,用于动态生成与客户通信的/SocketMySocket * m_ListenSocket; /定义MySocket类对象指针,用于动态生成监听Socketvoid OnReceive();void OnClose();
47、void OnAccept(); /要在主对话框代码中实现的服务器端功能的三个函数void SocketReset(); /重置销毁不再使用的套接字在ChatServerDlg.cpp中写出OnAccept()、OnClose()、OnReceive()三个函数的函数体,为它们的实现代码预留出空间,同时实现SocketReset函数,代码如下:void CChatServerDlg:SocketReset() /SocketReset函数实现 if(m_ServerSocket != NULL) delete m_ServerSocket; /在此要销毁两个Socket,一个是与客户通/信的S
48、ocketm_ServerSocket = NULL; if(m_ListenSocket != NULL)delete m_ListenSocket;/还有一个是监听Socketm_ListenSocket = NULL;试运行的界面如图2.44所示。(3)代码的复制、修改。l l 客户端。客户端。“连接”按钮事件过程代码如下:/初始化套接字,获取对话框指针if(!if(!AfxSocketInitAfxSocketInit()() MessageBoxMessageBox( (WindowSocketWindowSocket initial initial failed!,failed!,
49、Receive,MB_ICONSTOPReceive,MB_ICONSTOP); );return;return; m_ClientSocketm_ClientSocket = new = new MySocketMySocket; ;m_ClientSocketm_ClientSocket-GetDlgGetDlg(this);(this);/连接服务器BYTE nFild4;CString sIP;UpdateData();ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild
50、1,nFild2,nFild3);m_ClientSocketm_ClientSocket-Create();-Create();/ 创建客户端Socketm_ClientSocketm_ClientSocket-Connect(-Connect(sIP,sPortsIP,sPort); );/发起连接请求“断开”按钮事件过程代码如下:/断开与服务器的连接m_ClientSocketm_ClientSocket-Close();-Close();/关闭客户端SocketSocketResetSocketReset(); (); /避免指针悬空m_ListWords.AddString(从服务器
51、断开);“发送”按钮事件过程代码如下:UpdateData();m_ClientSocketm_ClientSocket-Send(m_sWords,m_sWords.GetLengthSend(m_sWords,m_sWords.GetLength();();/向服务器发送信息m_ListWords.AddString(发送: + m_sWords);m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1);“清空”按钮事件过程代码如下:/ADDm_ListWords.ResetContent();/ADDl#pragma oncel/ MySo
52、cket 命令目标l/ADDlclass CChatServerDlg;l/ADDlclass MySocket : public CAsyncSocketllpublic:lMySocket();lvirtual MySocket();lvirtual void OnClose(int nErrorCode);lvirtual void OnReceive(int nErrorCode);lvirtual void OnAccept(int nErrorCode);l/ADDl CChatServerDlg * m_dlg;lvoid GetDlg(CChatServerDlg * dlg)
53、;l/ADDl;l/ADDl#include ChatServerDlg.hl/ADDlvoid MySocket:GetDlg(CChatServerDlg *dlg) /获得窗口界面的指针llm_dlg=dlg;llvoid MySocket:OnClose(int nErrorCode)llm_dlg-OnClose();lCAsyncSocket:OnClose(nErrorCode);llvoid MySocket:OnReceive(int nErrorCode)llm_dlg-OnReceive();lCAsyncSocket:OnReceive(nErrorCode);llvo
54、id MySocket:OnAccept(int nErrorCode)llif(m_dlg-m_ServerSocket=NULL)lm_dlg-OnAccept();lCAsyncSocket:OnAccept(nErrorCode);ll/ADDl#include MySocket.hl/ADDlpublic:l/ADDlMySocket * m_ServerSocket;l MySocket * m_ListenSocket;lvoid OnReceive();lvoid OnClose();lvoid OnAccept();lvoid SocketReset();l/ADDl/ADD
55、lm_ServerSocket=NULL;lm_ListenSocket=NULL;l/ADDlvoid CChatServerDlg:SocketReset()llif(m_ServerSocket!=NULL)lldelete m_ServerSocket;lm_ServerSocket=NULL;llif(m_ListenSocket!=NULL)lldelete m_ListenSocket;lm_ListenSocket=NULL;lllvoid CChatServerDlg:OnClose()ll/关闭与客户端的通信信道lm_ListWords.AddString(客户端断开连接)
56、;lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);lm_ServerSocket-Close();/关闭与客户端通信的Socketlif(m_ServerSocket!=NULL)lldelete m_ServerSocket;lm_ServerSocket=NULL;lllvoid CChatServerDlg:OnReceive()ll/接收客户端发来的信息lchar szTemp200;lint n=m_ServerSocket-Receive(szTemp,200);/接收信息lszTempn=0;l CString sTemp;l
57、sTemp.Format(收到:%s,szTemp);lm_ListWords.AddString(sTemp);/显示信息lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);llvoid CChatServerDlg:OnAccept()ll/动态创建用于通信的Socketlm_ServerSocket=new MySocket;lm_ServerSocket-GetDlg(this);l/ 接受客户端的连接请求lm_ListenSocket-Accept(*m_ServerSocket);/接受连接请求lm_ServerSocket-Asy
58、ncSelect(FD_READ|FD_CLOSE);lm_ListWords.AddString(接受了一个客户端的连接请求);lm_ListWords.SetTopIndex(m_ListWords.GetCount()-1);ll/ADDl l 服务器端。服务器端。“开始监听”按钮事件过程代码如下:/初始化套接字,获取对话框指针if(!if(!AfxSocketInitAfxSocketInit()() MessageBoxMessageBox( (WindowSocketWindowSocket initial failed!, initial failed!,Send,MB_ICON
59、STOPSend,MB_ICONSTOP); );return;return; m_ListenSocketm_ListenSocket = new = new MySocketMySocket; ;m_ListenSocketm_ListenSocket-GetDlgGetDlg(this);(this);/监听开始,服务器等待连接请求的到来BYTE nFild4;CString sIP,sP;UpdateData();ServerIP.GetAddress(nFild0,nFild1,nFild2,nFild3);sIP.Format(%d.%d.%d.%d,nFild0,nFild1,n
60、Fild2,nFild3);sP.Format(%d,sPort);m_ListenSocketm_ListenSocket-Create(sPort,1,FD_ACCEPT,sIP);-Create(sPort,1,FD_ACCEPT,sIP);/创建服务端监听Socketm_ListenSocketm_ListenSocket-Listen(1); -Listen(1); /开始监听m_ListWords.AddString(监听开始:);m_ListWords.AddString(地址 + sIP + 端口 + sP);m_ListWords.AddString(等待客户端连接);“停止
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026南昌市劳动保障事务代理中心招聘2名项目外包服务人员考试备考题库及答案解析
- 2026黑龙江大庆市大同区统计局招聘公益性岗位人员1人考试备考题库及答案解析
- 2026江苏事业单位统考泰州市兴化市招聘54人考试备考题库及答案解析
- 2026贵州安顺市关岭自治县民族高级中学招聘教辅人员(办公室文员)1人笔试备考试题及答案解析
- 2026阳泉煤业(集团)有限责任公司总医院招聘47人笔试备考试题及答案解析
- 2026江西联通春季校园招聘笔试参考题库及答案解析
- 2026四川遂宁市就业服务管理局面向社会招聘1名编外人员笔试参考题库及答案解析
- 2026上海复旦大学化学系舒校坤课题组招聘全职博士后备考题库附答案详解ab卷
- 2026中国能建中电工程中南院春季校园招聘8人备考题库及参考答案详解【综合题】
- 2026四川大学华西医院许艺苧研究员课题组博士后招聘备考题库及参考答案详解(模拟题)
- 工程EPC总承包项目成本管控方案
- 电容储能螺柱焊机说明书
- 五输穴和临床应用
- 《Unit 1 Nice boys and girls》(教学设计)-2024-2025学年人教版PEP(一起)(2024)英语一年级下册
- 神经外科手术患者家属的照护指南
- 《质量、环境和职业健康安全管理体系程序文件》
- 一般情况皮肤淋巴结及头颈部检查课件
- 保护性约束相关管理制度
- 《汽车商品性主观评价方法 客车》
- 电气柜组装合同范例
- 《习近平新时代中国特色社会主义思想学生读本》第2讲《实现社会主义现代化和中华民族伟大复兴》-教案
评论
0/150
提交评论