基于Csocket的聊天程序_第1页
基于Csocket的聊天程序_第2页
基于Csocket的聊天程序_第3页
基于Csocket的聊天程序_第4页
基于Csocket的聊天程序_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

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

文档简介

基于Csocket的聊天程序实验四使用CSocket类的网络通信基础知识CSocket类是CAsyncSocket类的派生类,它提供了对通过CArchive对象使用套接字工作的更高级抽象。CSocket类的使用比CAsyncSocket类更加容易,它继承了CAsyncSocket类的许多封装了API的成员函数,并且管理了通信的大多数方面,这使用户从原来不得不使用原始API或者AsyncSocket类的繁杂工作巾解脱出来。更加重要的是CSocket类提供了对于同步操作CArchive对象十分重要的阻塞功能,且CSocket通过与类CSocketFile和CArchive一起来管理对数据的发送和接收,使收发数据的操作变得简单明了CSocket类是CAsyncSocket类的派生类,它对WinsockAPI进行进一步封装,因此它的成员函数比CAsyncSocket要少得多,不难掌握。(1)CSocket和Create这两个函数与CAsyncSocket类的同名成员函数的作用和用法相似。(2)IsBlocking该函数用来确定套接字当前是否有正在执行的阻塞调用,其原型为:BOOLIsBlocking();如果套接字处于阻塞状态,则返回非0值,否则返回0。(3)FromHandle该函数用于从给定的SOCKET句柄中得到相应的CSocket对象指针,其原型为:staticCSocket*PASCALFromHandle(SOCKEThSocket);其中,参数hSocket是给定的SOCKET句柄。如果函数调用成功,则返回CSocket对象指针,如果返回NULL,则该句柄没有与socket对象相连。(4)Attach该函数用于将SOCKET句柄与CSocket对象相连,其原型为:BOOLAttach(SOCKEThSocket):其中,hSocket用于知道欲与CSocket对象相连的SOCKET句柄。如果函数调用成功则返回非0值,否则返回0。(5)CancelBlockingCall该函数用于取消正存进行的阻塞调用,其原型为:voidCanceIBlockingCall();通过调用该函数,原始的阻塞调用将立即被中止,并返回错误码WSAEINTR。注意:如果阻塞是由Connect调用引起的,则虽然WindowsSockets将立即中止阻塞调用,但是除非连接完成或超时,否则套接字资源可能都不会被释放,而且除非1被取消的调用为Accept,否则该函数都将使套接字处于不确定的状态。(6)OnMessagePending重载该函数可以在Windows中寻找并响应特定的消息,其原型为:virtualBOOLOnMessagePending():如果该消息被处理,则返回非0值,否则返回0。共同使用CSocket与CArchive对象是最简单的套接字编程模型,其中CArchive对象将帮助程序员处理许多以前必须使用API或CAsyncSocket类来处理的通信问题,大大减少了编程的工作量。图1值得注意的是,尽管CSocketFile类是CFile的派生类,但它并不支持CFile的一些成员函数,例如Seek、GetLengh、SetLengh、LockRange、UnlockRange以及GetPosition等函数,这还是比较容易理解的,因为CSocketFile是从相关的CSocket对象中读出或写入字节序列,与文件无关,诸如Seek或GetPosition等函数并无意义。为了禁止CSocketFile所不支持的CFile成员函数在CSocketFile类中被重载,在执行重载这些函数时,就会触发一个CNotSupportedException异常。此外,CSocketFile也能单独使用(不与CArchive对象共I同使用)。默认情况下,CSocketFile的构造函数的bArchiveCompatible参数为TRUE,这指定了文件对象与归档一起使用。要使文件对象不与归档一起使用,只需将bArchiveCompatible设置为FALSE即可。不过,当CSocketFile与归档对象一起使用时,它具有更好的性能,并减少了“死锁”的危险。CSocket编程模型如图2所示。注意:CArchive对象只能单向传递数据:载入(接收)或存储(发送)。在某些情况下,用户越须使用两个CArchive对象,一个进行数据发送,而另一个进行数据2接收。并且CArchive类特别为CSocket类提供了IsBufferEmpty成员函数,如果缓冲区包含多个数据消息,例如,需要循环直到所有的数据都被读出,并且缓冲区被清空。否则,下一个将接收数据的通告可能被无限延迟。使用IsBufferEmpty函数,可以确定接收到了所有数据。此外,CSocket类也和CAsyncSocket-样提供了一些重载函数,包括:OnReceive、OnSend、OnAccept、OnConnect和OnClose并且CSocket类还提供了一个高级的重载函数OnMessagePending。MFC在套接宁响应Windows消息时调用该函数。可以重载OnMessagePending函数以从Windows寻找特定的消息并响应它们。它的默认版本是,当等待阻塞调用完成时,检查消息队列并寻找WM_PAINT消息,它发送重绘消息以便提高显示质量。因此假如要用到这些重载函数的话,一般需要从CSocket类派生自己的Socket类方能重载这些函数。本实验采用CSocket编程模型建立一个聊天程序的简单实例。使用vc++6建立一个基于对话框的工程,建立工程时注意选上“Windows套接字”复选框。图2编程模型编程步骤:3一、服务器端应用程序设计(工程名称SocSvr)1.1、界面及各控件属性界面如下:4各控件属性如下控件类型控件IDCaption属性控件变量变量类型列表框IDC_LST_Logm_lst_logCListBox编辑框IDC_EDT_SenMsgm_edt_senMsgCEdit按钮IDC_BTN_Sendm_btn_sendCButton列表框控件IDC_LST_Log的属性“sort”值为false,属性“HorizontalScroll”值为true。按钮IDC_BTN_Send属性Disable值为true。1.2、定义CSocket类的派生类CSocListen和CSocRecv从CSocket编程模型知道,服务器端需要两种套接字,一个用来侦听连接请求,一个用来与请求连接的套接字建立连接。因此,为程序添加两个CSocket派生类:SSocListen和CSocRecv,它们与对话框类密切配合,共同完成程序所要求实现的功能。在vc集成环境左侧的工程管理栏中,切换到“classview”页,对准“SocSvrClasses”点右键,在弹出的菜单中点击“newclass”,弹出“newclass”对话框。在此对话框的“Classtype”组合框中选择“MFCClass”,在“Baseclass”组合框中选择“CSocket”,然后再在“Name”文本框中填入类的名称“CSocListen”,点击“OK”按钮。这样,一个CSocket类的派生类“CSocListen”就创建好了。用同样的方法创建CSocket类的另一个派生类“CSocRecv”。创建过程的对话框如下图所示。51.3、建立套接字与对话框类的关联在程序中,对话框类要用到套接字类,而套接字类在响应某些消息,如在函数OnAccept、OnReceive中进行处理时,也要改变对话框的某些控件状态,以反映给用户这些事情的发生。这里存在着两个类相互使用的情况,把套接字类对象定义成对话框类的成员变量,同时在套接字类中也把对话框类定义为成员变量。如何实现这样的用法呢,在对话框类实现文件(cpp文件)中加入套接字头文件的声明,然后在套接字类实现文件(cpp文件)中加入对话框类头文件的声明,然后在对话框类的头文件里把套接字的指针变量定义为对话框的成员变量,再在套接字类的头文件里把对话框的指针变量定义为对该套接字的成员变量。具体做法应该如下:首先,在SocSvrDlg.h文件中加入套接字类头文件的声明,语句#pragmaonce的后面加入如下语句:classCSocListen;//声明侦听类classCSocRecv;//声明接收客户端消息类然后在该文件中为CSocSvrDlg类增加两个公有成员变量,语句如下:CSocListen*m_pCSocListen;//定义一个侦听类的指针6CSocRecv*m_pCSocRecv;//定义一个接收客户端消息类的指针再在SocSvrDlg.cpp文件中把两个套接字类的头文件包含进来:#include"SocListen.h"//侦听类,包含进来#include"SocRecv.h"//接收客户端消息类,包含进来这样在对话框类中就可以使用套接字类了。接下来在套接字类中加入对话框类信息。首先,在SocListen.h文件的开头,语句#pragmaonce的后面加入如下语句:classCSocSvrDlg;//声明对话框类然后,在该文件中为CSocListen类添加一个公有成员变量和一个构造函数:CSocListen(CSocSvrDlg*pDlgSocSvr);CSocSvrDlg*m_pDlgSocSvr;接着在SocListen.cpp文件中添加新的构造函数的实现,并添加一条关于SocSvrDlg.h文件的预编译声明,代码如下:#include"SocSvrDlg.h"//对话框类,包含进来CSocListen::CSocListen(CSocSvrDlg*pDlgSocSvr){m_pDlgSocSvr=pDlgSocSvr;//初始化对话框指针}这样,在套接字类中也可以通过成员变量使用对话框了。使用同样的方法对CSocRecv类进行设置,使其也可以通过成员变量使用对话框。1.4、为套接字添加串行化读写信息的功能在服务器端的两个套接字中,只有CSocRecv套接字是真正与客户端套接字建立连接,发送与接收数据的,因此,我们只为该类添加串行化读写信息功能。在SocRecv.h文件中为类CSocRecv添加三个公有成员变量。CsocketFile*m_pCSocFile;Carchive*m_pCArcIn;Carchive*m_pCArcOut;1.5、在对话框中初始化套接字并侦听连接请求在OnInitDialog函数中添加如下代码:if(m_pCSocListen=newCSocListen(this)){if(m_pCSocListen->Create(1000))//创建端口号{m_lst_log.AddString("等待连接„„");m_pCSocListen->Listen();}else{7m_lst_log.AddString("初始化失败,请重新启动程序");deletem_pCSocListen;//清除侦听socket所占内存}}else{m_lst_log.AddString("初始化失败,请重新启动程序");}上述代码主要是创建并初始化ServSock套接字,并开始侦听连接请求。1.6、接受连接请求由于是CSocListen类的*m_pCSocListen对象在侦听连接请求,因此由该类来接受连接请求。首先,在SocListen.h文件中加入如下语句:#iinclude“SocRecv.h”然后,重载该类的OnAccept函数,在该函数中添加如下代码:CSocRecv*pCSocRecv;//接收客户端消息类指针if(pCSocRecv=newCSocRecv(this->m_pDlgSocSvr)){if(Accept(*pCSocRecv)){pCSocRecv->m_pCSocFile=newCSocketFile(pCSocRecv);pCSocRecv->m_pCArcIn=newCArchive(pCSocRecv->m_pCSocFile,CArchive::load);pCSocRecv->m_pCArcOut=newCArchive(pCSocRecv->m_pCSocFile,CArchive::store);m_pDlgSocSvr->m_pCSocRecv=pCSocRecv;pCSocRecv=NULL;m_pDlgSocSvr->m_lst_log.AddString("连接成功,可以开始传递消息咯~");m_pDlgSocSvr->m_btn_send.EnableWindow(TRUE);}else{m_pDlgSocSvr->m_lst_log.AddString("试图连接客户端失败~");deletepCSocRecv;}}else{m_pDlgSocSvr->m_lst_log.AddString("连接套接字初始化失败~");}上述代码首先调用Accept函数接受连接请求,然后为该连接创建一个CSocRecv8类型的套接字,并为该套接字关联CArchive对象,使其能实现串行化传输信息的功能。最后把关联好的套接字传回给对话框对象供其使用。这样,对话框对象的成员变量RecvSock套接字便与客户端套接字之间建立了一条信息通道,信息将在两个套接字之间传递。1.7、接收信息连接建立成功后,当有信息到达服务器端时,就会引发SocRecv套接字对象的OnReceive函数,因此需要重载CSocRecv类的OnReceive函数。添加代码如下:CStringcsRecMsg;//接收到的信息(*m_pCArcIn)>>csRecMsg;//接收信息m_pDlgSocSvr->m_lst_log.AddString("客户端发来的信息如下:");m_pDlgSocSvr->m_lst_log.AddString(csRecMsg);//添加到列表框//选中列表框中刚刚收到的消息m_pDlgSocSvr->m_lst_log.SetCurSel(m_pDlgSocSvr->m_lst_log.GetCount()-1);1.8、发送信息为对话框“发送”按钮添加事件处理函数OnBTNSend(),代码如下:voidCSocSvrDlg::OnBTNSend(){//TODO:AddyourcontrolnotificationhandlercodehereCStringcsSenMsg;//要发送的消息m_edt_senMsg.GetWindowText(csSenMsg);//获得编辑框内容if(csSenMsg==""){AfxMessageBox("空字符串,不能发送~");return;}m_lst_log.AddString("你发出的信息如下:");m_lst_log.AddString(csSenMsg);m_lst_log.SetCurSel(m_lst_log.GetCount()-1);*(m_pCSocRecv->m_pCArcOut)<<csSenMsg;m_pCSocRecv->m_pCArcOut->Flush();}9二、客户端应用程序设计(工程名称SocClt)2.1、界面及各控件属性界面如下:各控件属性如下控件类型控件IDCaption属性控件变量变量类型列表框IDC_LST_Logm_lst_logCListBox编辑框IDC_EDT_SenMsgm_edt_senMsgCEdit按钮IDC_BTN_Sendm_btn_sendCButton列表框控件IDC_LST_Log的属性“sort”值为false,属性“HorizontalScroll”值为true。按钮IDC_BTN_Send属性Disable值为true。2.2、创建套接字类(从CSocket类派生)客户端只需要一个套接字,命名为CSocSend。2.3、建立对话框类与套接字类的关联首先,在SocCltDlg.h文件的开头,语句#pragmaonce后面加入如下语句:classCSocSend;//声明socket类然后,在该文件中为CSocCltDlg类添加一个公有成员变量,语句如下:10CSocSend*m_pCSocSend;//定义socket类指针再在CsocSend中添加对话框类的成员变量。首先,在SocSend.h文件的开头,语句#pragmaonce后面加入如下语句:classCSocCltDlg;//声明对话框类然后,在该文件中为CSocSend类添加一公有成员变量和一个构造函数,语句如下:CSocSend(CSocCltDlg*pDlgSocClt);CSocCltDlg*m_pDlgSocClt;//定义一个对话框类的指针接着,在SocSend.cpp文件中添加新的构造函数的实现代码,并添加一条关于CSocCltDlg.h文件的预编译声明,代码如下:#include"SocCltDlg.h"//对话框类,包含进来CSocSend::CSocSend(CSocCltDlg*pDlgSocClt){m_pDlgSocClt=pDlgSocClt;}这样,便完成了对话框和套接字之间的连接了。2.4、为套接字添加串行化读写信息的功能在SocSend.h文件中,为类CSocSend添加三个公有成员变量,代码如下:CSocketFile*m_pCSocFile;CArchive*m_pCArcIn;CArchive*m_pCArcOut;2.5、在对话框中初始化套接字并建立连接在对话框类的OnInitDialog函数中添加如下代码m_lst_log.AddString("正在连接„„");if(m_pCSocSend=newCSocSend(this)){if(m_pCSocSend->Create())//创建套接字{//if(m_pCSocSend->Connect("localhost",1000))//服务器名称、端口号if(m_pCSocSend->Connect("cy-sys",1000))//服务器名称、端口号{m_pCSocSend->m_pCSocFile=newCSocketFile(m_pCSocSend);m_pCSocSend->m_pCArcIn=newCArchive(m_pCSocSend->m_pCSocFile,CArchive::load);m_pCSocSend->m_pCArcOut=newCArchive(m_pCSocSend->m_pCSocFile,CArchive::store);m_lst_log.AddString("连接成功,可以开始传递消息咯~");m_btn_send.EnableWindow(TRUE);}else11{m_lst_log.AddString("连接不成功~");deletem_pCSocSend;//清除socket所占内存}}else{m_lst_log.AddString("初始化失败,请重新启动程序");deletem_pCSocSend;//清除socket所占内存}}else{m_lst_log.AddString("初始化失败,请重新启动程序");}2.6、接收消息消息到来时,会引发套接字的OnReceive消息

温馨提示

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

评论

0/150

提交评论