VC++ Socket网络通信编程
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(2)服务器端源码(ChatServerDlg.cpp文件中)。 “开始监听”按钮的事件过程如下:
//监听开始,服务器等待连接请求的到来 BYTE nFild[4]; CString sIP,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); //创建服务端监听 Socket m_ListenSocket.Listen(1); //开始监听 m_ListWords.AddString("监听开始:"); m_ListWords.AddString("地址" + sIP + " 端口" + sP); m_ListWords.AddString("等待客户端连接……"); Listen()函数用于侦听连接请求,原型为: BOOL Listen(int nConnectionBackloh = 5);
2.2.1 客户—服务器方式(C/S模式) 1.网络软件的通用体系结构 客户(Client)和服务器(Server)是指通信中所涉及的两个应用进程。客 户—服务器方式所描述的是进程之间服务和被服务的关系。在图2.3中,主机A运 行客户程序而主机B运行服务器程序。
2.最简单的Socket通信流程 一个只有客户方向服务方发信息的单向通信,并且也只有客户方会主动提出断 开连接的最简单的情形(相反过程的原理是一样的),其双方Socket之间的关系如 图2.4所示。
用相同的方法设置服务器端的用户界面如图2.17所示,也一样为IP地址控件 关联变量ServerIP,为文本框控件关联int型变量sPort,为列表框关联变量 m_ListWords。
6.雏形程序试运行 到此为止,这个程序的雏形已经形成,分别运行客户和服务器端的工程如图 2.18所示。
7.程序代码的组织 接下来就要为这个程序雏形注入灵性,添加核心源代码了。在此之前,先来 回顾一下前面设计的那个最简单的Socket通信流程,如图2.19所示。
创建类名为CClientSocket的客户Socket对象,下面给工程添加类,选择菜单 命令“项目”→“添加类”,如图2.7所示。
在弹出的“添加类”对话框中选择“MFC类”项,单击“添加”按钮(如图 2.8所示)。
在“MFC类向导”对话框中输入类名CClientSocket,向导将自动为这个添加 的类生成名为“ClientSocket.h”和“ClientSocket.cpp”的头文件和源文件,如 图2.9所示。
客户端也可以随时主动断开通信连接,下面是“断开”按钮的事件过程: //断开与服务器的连接 m_ClientSocket.Close(); //关闭客户端Socket m_ListWords.AddString("从服务器断开"); Close()函数用来关闭套接字并释放Socket描述符,其函数原型为: virtual void Close(); 客户端可以向服务器发送信息,“发送”按钮的事件过程为: //向服务器发信息 UpdateData(); m_ClientSocket.Send(m_sWords,m_sWords.GetLength()); //发信息 m_ListWords.AddString("发送:" + m_sWords); m_ListWords.SetTopIndex(m_ListWords.GetCount() - 1); Send()函数通过数据报或者数据流向对方套接字发送数据,其函数原型为: virtual int Send(const void* lpBuf, int nBufLen, int nFlags = 0);
反过来要使Socket能够访问到主界面上的控件,以便能够将自己的状况随时反映 给主程序并在主界面上显示出来,也需要在Socket源文件ClientSocket.cpp中添加头 文件声明: #include "ChatClientDlg.h" 同理,要使服务端程序能够创建和控制本地的Socket,也要在服务端工程界面控 制模块的头文件ChatServerDlg.h中添加如下代码:
#include "ListenSocket.h" #include "ServerSocket.h" CServerSocket m_ServerSocket; CListenSocket m_ListenSocket; //使主界面程序能够访问监听Socket类的代码文件 //使主界面程序能够访问服务Socket类的代码文件 //为了后面与客户通信而定义的Socket成员变量 //为了监听客户端的连接请求而定义的Socket成员变量
类 名
Socket对象 客户Socket 监听Socket 服务Socket
CClientSocket CListenSocket CServerSocket
2.创建工程和套接字对象 首先创建客户端工程。打开Visual Studio 2008环境,建立一个新的基于对话 框的MFC项目,项目名称为ChatClient,接着一直单击“下一步”按钮,直到设 置程序“高级功能”对话框,如图2.6所示。
头文件ChatClientDlg.h中添加如下两行代码:
#include "ClientSocket.h" //使主界面程序能够访问Socket类的代码文件 CClientSocket m_ClientSocket;//为了后面与服务器通信而定义的Socket成员变量
以上两行代码的添加位置如图2.13所示中“//ADD”记号之间标出的部分。
从上面已经标注了所用函数的通信流程图,可以进一步得出下面的源程序代 码组织框图(如图2.20所示)。
8.源代码完全剖析 (1)客户端源码。 客户端用户首先主动发起连接,以下是“连接”按钮的事件过程,位于 ChatClientDlg.cpp文件中: //连接服务器 BYTE nFild[4]; CString sIP; 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(); //创建客户端Socket m_ClientSocket.Connect(sIP,sPort); //发起连接请求
1. CAsyncSocket类 CAsyncSocket类是从MFC的根类CObject派生出来的,它在较低的级别上封 装Windows Socket API。 CAsyncSocket类在MFC套接字类中的继承位置如图2.2所示。 CAsyncSocket类的成员函数如表2.1所示。
2.CSocket类及其相关类 (1)CSocket类。 CSocket类是从CAsyncSocket派生而来的,它继承了CAsyncSocket对 Windows Socket API的封装。 (2)CSocket与CArchive、CSocketFile类的配合使用。 用CSocket类编写网络程序,既可以使用如CAsyncSocket类网络程序一样的 Send和Receive函数来收发信息,也可以与CSocketFile类和CArchive类一起来管 理对数据的发送和接收。
单击“完成”按钮,可以在类视图中看到刚刚添加的类CClientSocket(如 图2.10所示)。
3.理清程序文件的组织结构 (1)客户端程序文件。 打开已经创建好的客户端工程,在解决方案资源管理器中可以看到工程的所 有程序文件(如图2.11所示)。
全部程序文件可以分成三类:
第一类是.h后缀的பைடு நூலகம்文件,用来集中声明定义程序中用到的类、变
2.1 MFC及其Socket类
2.2 C/S模式下网络程序的Socket通信实例
2.3 与第三方程序的互通及Socket编程的本质
2.1.1 MFC简介 MFC,微软基础类(Microsoft Foundation Classes),同VCL类似, 是一种应用框架(Application Framework),随微软Visual C++ 开发 工具发布。 MFC是很庞大的,如最新版本中包含了大约两百多个不同的类(如图 2.1所示)。
以上四行代码的添加位置如图2.14所示中“//ADD”记号之间标出的部分。
5.布局简洁的界面 在客户端“资源视图”展开的目录树下双击Dialog文件夹下第二个项目,转 到用户界面设计工作区(如图2.15所示)。
完成的客户端简化界面(如图2.16所示)上,包括IP地址控件、列表框各1个, 文本框两个,四个按钮。
Connect()函数用于未连接的数据流或者数据报套接字建立连接。其函数原型为:
BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort); BOOL Connect(const SOCKADDR*lpSockAddr, int nSockAddrLen);
在类视图中选中CClientSocket,在界面右下角的属性窗口中单击“重写”按 钮,就可以为该Socket类编写被动响应网络事件的函数(如图2.21所示)。
选择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);
Create()函数用来创建和初始化套接字,具体过程为:构造套接字对象 m_ClientSocket后,调用Create()成员函数创建Socket句柄,并调用Bind()成员函 数将其与指定的地址绑定,Create()函数原型为:
BOOL Create(UINT nSocketport = 0, int nSocketType = SOCK_STREAM, long lEvent = FD_READ ︱FD_WRITE︱FD_OOB︱FD_ACCEPT︱FD_CONNECT︱FD_CLOSE, LPCTSTR lpszSocketaddress = NULL);
量、函数、宏等;
第二类是.cpp后缀的源文件,这是程序代码的主体,集中存放程序
的源代码;
第三类是资源文件,存放程序中用到的资源,如图标、图像、音频、
视频等,
(2)服务器端的源文件。 同理,服务器端也对应这几种程序文件,打开服务器工程,可以看到它们(如 图2.12所示)。
4.用头文件和类对象将程序源文件联成有机整体 例如,已经创建了各个Socket对象并且也有了它们各自对应的程序文件,但这 些文件仍然是孤立的,相互之间的代码无法访问,要使它们能联系在一起,使控制 程序的主文件能够自如地操纵Socket,就必须通过头文件声明和创建类对象成员 变量将各个类联成有机的整体。 要使客户端程序能够创建和控制本地的Socket,在客户端工程界面控制模块的
由上面这个十分简单的过程很容易得出最简单的Socket通信流程,如图2.5所 示。
1.对象分析 由2.2.1节分析的最简单的Socket通信流程可见,要实现这样一个完整流程需 要三个套接字对象:客户端一个(我们称为“客户Socket”),服务器端两个(一 个用于监听,称为“监听Socket”;另一个用于接收客户发来的信息,称为“服务 Socket”),这三个套接字对象对应三个Socket类,都继承自CAsyncSocket,分 别给它们取名如表2.2所示。