11.2.3 封装CData类
在11.2.2节中,分别向用户介绍了服务器端和客户端的各个功能实现方法。为了让用户深入了解C++(www.cppentry.com)面向对象编程(www.cppentry.com)的方法,在本节中,将各个功能函数封装在CData类中。使用时,直接生成CData类实例对象,通过该对象调用相关的功能函数。
1.定义CData类
首先,用户需要定义CData类头文件Data.h。代码如下:
- class CData
- {
- public:
- CData(); //构造函数
- void bind(); //服
务器绑定套接字函数 - void sevsend(SOCKET&,char*,int,int); //服务器发送函数
- void sevrecv(SOCKET&,char*,int,int); //服务器接收函数
- void connect(); //客户端连接函数
- void send(SOCKET&,char*,int,int); //客户端发送函数
- void recv(SOCKET&,char*,int,int); //客户端接收函数
- ~CData();
- };
然后,在定义文件Data.cpp中,实现各个功能函数的具体方法。代码如下:
- #include "Data.h"
- #include "iostream.h"
- CData::CData() //构造函数
- {
- }
- void CData::bind() //服务
器绑定套接字函数 - {
- WSADATA data; //定义结构体变量
- CString name; //定义主机名字符串
- DWORD ss=MAKEWORD(2,0); //指定套接字版本
- ::WSAStartup(ss,&data); //初始化套接字库
- s=::socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
- //创建套接字
- sockaddr_in addr; //定义地址结构变量
- ::gethostname((char*)&name,(int)sizeof(name)); //获得主机名字
- hostent *p=::gethostbyname((char*)&name); //从主
机名获取主机地址 - in_addr *a=(in_addr*)*p->h_addr_list; //获得本机IP地址
- CString str14=::inet_ntoa(a[0]); //转换字符串IP地址
- addr.sin_family=AF_INET; //填充地址结构
- addr.sin_port=htons(80); //指定监听端口为80
- addr.sin_addr.S_un.S_addr=inet_addr(str14);//指定主机IP地址
- ::bind(s,(sockaddr*)&addr,sizeof(addr)); //将
本地信息绑定到套接字 - ::listen(s,5); //监听
- WSAAsyncSelect(s,this->m_hWnd,WM_SOCK,FD_ACCEPT|FD_READ);
- //将套
接字设置为异步模式 - }
- void CData::sevsend(SOCKET s,char* buff,int len,int flags)
- //自定
服务器发送函数 - {
- send(s,buff,len,flags); //调用API发送函数
- }
- void CData::sevrecv(SOCKET s,char* buff,int len,int flags)
- //自定
义服务器接收函数 - {
- recv(s,buff,len,flags); //调用API接收函数
- }
- void CData::connect()
- {
- sockaddr_in addr; //定义地址结构变量
- addr.sin_family=AF_INET; //填充地址结构
- addr.sin_port=htons(80); //指定监听端口为80
- addr.sin_addr.S_un.S_addr=inet_addr(str14); //指定主机IP地址
- if(connect(s,( sockaddr*)addr,sizeof(addr),NULL)==-1)
- //连接服务器
- {
- MessageBox("连接服务器失败!"); //提
示用户连接服务器失败 - }
- }
- void CData::send(SOCKET s,char* buff,int len,int flags)
- //自定客户端发送函数
- {
- GetDlgItem(IDC_EDIT1)->GetWindowText(str);
- //获取用户输入的数据
- send(s,str.GetBuffer(1),sizeof(str),NULL);
- //发送信息
- GetDlgItem(IDC_EDIT2)->GetWindowText(str1);
- //获取
信息显示框中的内容 - str1+="\r\n"; //添加回车换行符
- str1+=str; //连接字符串
- GetDlgItem(IDC_EDIT2)->SetWindowText(str1);
- //设置
信息显示框的内容 - }
- void CData::recv(SOCKET s,char* buff,int len,int flags)
- //自定
义客户端接收函数 - {
- char buff[1024]; //定义字符缓冲区
- memset(&buff,0,1024); //初始
化字符缓冲区 - recv(s,&buff,1024,NULL); //接收数据
- }
- void CData::~CData() //析构函数
- {
- }
上面的代码已经基本实现了自定义CData的基本方法。用户在使用该类时,必须在程序中包含该头文件Data.h。否则,用户将不能正确使用自定义类CData。
2.使用CData类
用户在程序需要使用自定义类CData时,首先需要包含该类头文件。代码如下:
- ... //省略部分代码
- #include "Data.h" //包含自定义类头文件
注意:在VC中包含头文件时,如果所包含的头文件是系统定义的头文件,则使用符号"< >"括起来。否则,使用符号"" ""括起来。
然后,再定义自定义类对象。代码如下:
- ... //省略部分代码
- CData dat; //定义类对象
完成以上步骤后,用户便可以在程序中使用该对象调用相关的成员函数了。例如,当服务器端转发消息时,应该使用CData类中服务器发送函数对消息进行发送。代码如下:
- void CQQDlg::Onsoc(WPARAM wParam,LPARAM lParam)
- {
- switch (lParam) //判断套接字事件
- {
- ... //省略部分代码
- case FD_READ: //套接字读取事件
- {
- ... //省略
部分读取事件响应代码 - for(int i=0;i<5;i++)
- {
- if(msg[i].qq.m_name1== m_list.GetItemText(i,3))
- //判断昵称是否存在
- {
- dat.send(msg[i].s,&msg[i].qq.msg,1024,NULL);
- //使用
对象将信息转发到接收方 - }
- }
用户使用自定义类CData中的成员时,仅需要使用该类对象对函数进行调用即可。所以,在本节中,不再对该类中其他的成员函数进行举例调用,请用户自行参考随书光盘中的实例代码。