POP3客服端实例论文期末作业.docx
《POP3客服端实例论文期末作业.docx》由会员分享,可在线阅读,更多相关《POP3客服端实例论文期末作业.docx(33页珍藏版)》请在冰豆网上搜索。
POP3客服端实例论文期末作业
目录
(一):
背景知识、主要函数的描述2
一:
POP3简介2
二:
POP3协议工作原理2
三:
程序实现的技术要点(主要函数)3
1.运用Windows的消息驱动机制3
2.通过状态转换来控制会话命令的发布顺序4
3.用结构向量来缓存信件信息4
(二)程序流程图和主要思想5
POP3的会话过程5
POP3程序实例的流程图6
(三)创建应用程序的过程7
1.使用MFCAppWizard创建应用程序框架7
2.为对话框添加控件9
3.定义控件的成员变量10
4.为对话框中的控件对象添加事件响应函数12
5.为类添加其它的成员和创建CAsyncSocket类12
(四)程序代码清单15
(五)程序运行结果27
(一):
背景知识、主要函数的描述
一:
POP3简介
POP适用于C/S结构的脱机模型的电子邮件协议,已发展到第三版,称POP3。
POP3协议允许用户以一定的方式从保存邮件的服务器(即POP3服务器)上取走自己的邮件。
该协议用于接收邮件的双方(客户机、POP3服务器)进行通信。
使用该协议,用户可以脱机阅读信件。
二:
POP3协议工作原理
POP3提供了一种客户机/服务器脱机模型,客户机通过向服务器发送一些命令来完成相应的操作。
客户机能够发送的命令与它所处的状态有关。
协议中定义了三种状态:
即确认状态(AuthorizationState)、处理状态(TransactionState)和更新状态(UpdateState)。
在不同的状态下,客户机可以向服务器发送的命令是有区别的,某些命令还会导致状态的转换。
POP3服务器一般使用的是TCP的110号端口。
当客户机与服务器建立TCP连接时,POP3服务器向客户机发回一个问候,交互过程即进入确认状态。
此时,若客户机提供了自己的身份并成功确认,即由确认状态转入处理状态;在这个状态,用户可用相应的命令处理自己的邮件。
在完成相应的处理过程后客户机发出QUIT命令,则进入更新状态;在此状态下,POP3服务器释放邮件资源并返回一个告别响应;最后关闭TCP连接。
三:
程序实现的技术要点(主要函数)
1.运用Windows的消息驱动机制
除了由MFC创建的应用程序类和对话框类以外,程序从CAsyncSocket类派生了自己的套接字类,并为它添加了OnConnect()、OnClose()和OnReceive()三个事件处理函数。
程序的会话过程几乎完全是由FD_READ消息驱动的。
建立连接后,服务器会返回信息,接到命令后,服务器也会返回信息。
当信息到达客户端套接字的接收缓冲区时,会触发FD_READ消息,并自动执行OnReceive()函数。
该函数接收服务器发来的信息,进行分析处理,然后再发送相应的命令。
这命令又会引来服务器的响应,又会触发客户端的FD_READ消息。
如此周而复始,完成POP会话的全过程。
2.通过状态转换来控制会话命令的发布顺序
程序定义了一个枚举类型STATE,并为套接字类定义了一个STATE类型的变量state,用来表示POP会话的实际状态。
容易看出,枚举的成员符号是客户端向POP3服务器发送的命令。
typedefenum
{FIRST=0,USER,PASS,STAT,LIST,RETR,ENDRETR,DELE,GOO}
STATE;
STATEstate;
当用户点击“连接”按钮与服务器建立TCP连接时,将state置为初值FIRST;然后,每当收到服务器的信息,一方面根据会话的当前状态作响应的分析处理,决定应当继续发送哪条命令,另一方面发出下一个命令以后,改变state的值,将它置为该命令的状态对应的值,这就实现了会话过程中的状态转换,并保证会话按照既定的顺序进行。
读者可仔细分析mySock:
:
AnalyzeMsg()函数。
3.用结构向量来缓存信件信息
首先程序定义了一个结构类型,用来缓存一封信件信息。
typedefstruct
{
CStringtext;//存储信件的文本
intmsgSize;//信件的大小
intretrSize;//信件实际下载的大小,在下载过程中动态变化
}MESSAGEPROP;
然后为套接字类定义了一个向量型的成员变量,相当于一个数组,其成员是上述的结构。
vectormsgs;在pop会话中,一次性地将信箱中所有信件的信息转入这个向量,然后可以查阅,存储到文件中,或者进行其他处理。
(2)程序流程图和主要思想
POP3的会话过程
POP3使用C/S工作模式,在接收邮件的用户的PC中,运行POP3程序,在用户所在的ISP的邮件服务器中运行POP3程序,二者之间按照POP3互发消息,POP3的客服机发给POP3服务器的消息成为命令,交互的过程就是POP3回话。
POP3接收者对POP3发送者进行初始化连接,发送者对接收者发送询问指READY,接收者则向发送者提交所要接收数据的要求,发送者做出回应,发送数据。
接收者则开始接收数据。
发送者发送完数据后,提出断开请求,并断开连接。
数据接收过程完成。
POP3程序实例的流程图
POP3接收者对POP3发送者进行初始化连接,接着进行由POP3的发送者对服务器连接,若失败进行错误处理;连接成功,登录自己的邮箱账户,成功后POP3的接收者就可以与发送者进行对话,也即就可以查看自己的邮箱邮件;如失败,依然进行错误处理,直到结束退出。
通过POP3命令查询电子邮件时,客户机可以下载指定的邮件,然后对邮件进行删除或修改操作都无需与服务器进一步交互。
客户机向服务器发送命令并等待响应,POP3命令采用命令行形式,用ASCII码表示。
服务器响应是由一行或多行组成,其中,第一行以ASCII文本+OK,或-ERR开始,分别指出相应的操作是成功还是失败。
(3)创建应用程序的过程
1.使用MFCAppWizard创建应用程序框架
工程名是pop3,应用程序的类型是基于对话框的,对话框的标题是“接收电子邮件客户端程序”,需要WindowsSockets的支持,其它部分接受系统的默认设置就可以。
向导自动为应用程序创建了两个类:
应用程序类:
CPop3App,基类是CWinApp,对应的文件是pop3.h和pop3.cpp。
对话框类:
CPop3Dlg,基类是CDialog,对应的文件是pop3Dlg.h和pop3Dlg.cpp。
2.为对话框添加控件
在程序的主对话框界面中按照图7.6添加相应的可视控件对象,并按照表1.0修改控件的属性。
表1.0对话框中的控件属性
控件类型
控件ID
Caption
静态文本statictext
IDC_STATIC
pop3服务器地址
静态文本statictext
IDC_STATIC
用户名
静态文本statictext
IDC_STATIC
口令
编辑框editbox
IDC_EDIT_SERVER
编辑框editbox
IDC_EDIT_USER
编辑框editbox
IDC_EDIT_PASS
复选框CheckBox
IDC_CHECK_DEL
删除邮箱中的邮件
多文本框RichEditBox
IDC_RICH_INFO
组合选择框ComboBox
IDC_COMB_LIST
(DropList型)
命令按钮button
IDC_BTN_CONN
连接
命令按钮button
IDC_BTN_DISC
断开
命令按钮button
IDCANCAL
取消
命令按钮button
IDC_BTN_VIEW
查看邮件
命令按钮button
IDC_BTN_SAVE
存储
由于属性较多,截取2个图表示一下:
3.定义控件的成员变量
用类向导(ClassWizard)为对话框中的控件对象定义相应的成员变量
控件ID
ControlIDs
变量名称
MemberVariableName
变量类别
Category
变量类型
VariableType
IDC_EDIT_SERVER
m_strServer
Value
CString
IDC_EDIT_USER
m_strUser
Value
CString
IDC_EDIT_PASS
m_strPass
Value
CString
IDC_CHECK_DEL
m_bolDel
Value
BOOL
IDC_COMB_LIST
m_ctrList
Control
CComboBox
IDC_RICH_INFO
m_Info
Value
CString
m_ctrlnfo
Control
CRichEditCtrl
4.为对话框中的控件对象添加事件响应函数
用类向导(ClassWizard)为对话框中的控件对象添加事件响应函数。
控件类型
对象标识ObjectID
消息Message
函数Memberfunctions
命令按钮
IDC_BTN_CONN
BN_CLICKED
OnBtnConn
命令按钮
IDC_BTN_DISC
BN_CLICKED
OnBtnDisc
命令按钮
IDC_MSGLIST
BN_CLICKED
OnDropdownMsglist
命令按钮
IDC_MSGLIST
CBN_CLOSEUP
CloseupMsglist
5.为类添加其它的成员和创建CAsyncSocket类
为了能够捕获并响应socket事件,应创建用户自己的套接字类,可利用类向导添加。
ClassType选择MFCClass,类名为mySock,基类是CAsyncSocket类,创建后对应的文件是mysock.h和mysock.cpp。
在利用类向导为mysock类添加OnConnect,OnClose和OnReceive三个事件处理函数,并为它添加一般的成员函数和变量。
可参看下一小节的程序代码。
最后是,手工添加包含语句以及事件函数和成员函数的代码和分阶段编译执行,进行测试。
添加包含语句以及事件函数和成员函数
分阶段编译执行,进行测试。
(4)程序代码清单
//Pop31.cpp:
implementationoftheCPop3class.
#include"stdafx.h"
#include"Gniazdo.h"
#include"pop3Dlg.h"
#include"Pop31.h"
#ifdef_DEBUG
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#definenewDEBUG_NEW
#endif
#defineMAX_BUFF20000
CPop3:
:
CPop3()
{
state=FIRST;
error="Notconnectedtoserver\r\n";
delAfterRead=FALSE;
}
CPop3:
:
~CPop3()
{
}
voidCPop3:
:
OnReceive(interr)
{
if(err==0)//ifnoerror
{
charbuff[MAX_BUFF];
intrec=Receive(buff,MAX_BUFF);//receivedata
buff[rec]=NULL;
lastMsg=buff;
ParseMsg();//parsedata
}
else
{
error="Errorwhilereceiving!
\r\n";
((DLG)m_pWnd)->Dispatch(S_CLOSE);
}
}
voidCPop3:
:
GetLastMsg(CString&s)
{
s=lastMsg;
}
voidCPop3:
:
SetProp(CStringu,CStringp)
{
user=u;
pass=p;
}
voidCPop3:
:
ParseMsg()
{
CStrings;
strstreamstr;
stringcheck;
str<<(LPCSTR)lastMsg;
str>>check;
if(check=="-ERR")//如果有错误
{
error="Received-ERRfromserver:
"+lastMsg;
Close();//断开然后关闭
return;
}
switch(state)//如果没有错误,则根据不同的响应来处理
{
caseFIRST:
//如果已经连接成功,类初始化的时候state为FIRST
msgs.clear();
((DLG)m_pWnd)->Dispatch(S_RECEIVE);//发送消息到窗体
s.Format("user%s%c%c",user,13,10);
Send((LPCSTR)s,s.GetLength());//发送用户帐号
state=USER;
break;
caseUSER:
((DLG)m_pWnd)->Dispatch(S_RECEIVE);
s.Format("pass%s%c%c",pass,13,10);
Send((LPCSTR)s,s.GetLength());//发送密码
state=PASS;
break;
casePASS:
((DLG)m_pWnd)->Dispatch(S_RECEIVE);
s.Format("stat%c%c",13,10);
Send((LPCSTR)s,s.GetLength());//发送stat命令
state=STAT;
break;
caseSTAT:
{
strings1;
str.seekg(0);
str>>s1>>numMsg>>sizeMsg;//获得数量和大笑
flush(str);
((DLG)m_pWnd)->Dispatch(S_GETNUMMSGS);
((DLG)m_pWnd)->Dispatch(S_GETSIZEMSGS);
if(numMsg>0)//如果有邮件,则发送RETR获得邮件信息
{
state=RETR;
s.Format("retr1%c%c",13,10);
retrMsg=1;
MESSAGEPROPprop;
prop.msgSize=0;
prop.retrSize=0;
prop.text="";
msgs.push_back(prop);
Send((LPCSTR)s,s.GetLength());
}
else//如果没有邮件,则断开
{
error="Nonewmessages\r\n";
Close();
}
}
break;
caseRETR:
{
if(msgs[retrMsg-1].msgSize==0)//如果第一次接收到数据
{
stringtemp;
str.seekg(0);
str>>temp>>msgs[retrMsg-1].msgSize;//得到信息大小
}
msgs[retrMsg-1].text+=lastMsg;//保存数据
msgs[retrMsg-1].retrSize+=lastMsg.GetLength();//增加数据大小
if(msgs[retrMsg-1].retrSize>=msgs[retrMsg-1].msgSize)//判断是否获得所有数据
{//检查是否有其他邮件
if(retrMsg{
MESSAGEPROPprop;
prop.msgSize=0;
prop.retrSize=0;
prop.text="";
msgs.push_back(prop);
retrMsg++;
s.Format("retr%d%c%c",retrMsg,13,10);//requestanother
Send((LPCSTR)s,s.GetLength());
}
else
{
//如果全部接收完毕,判断是否要删除
if(delAfterRead&&numMsg>0)
{
state=DELE;
delMsg=1;
s.Format("dele%d%c%c",delMsg,13,10);
Send((LPCSTR)s,s.GetLength());
}
else//否则退出
{
state=ENDRETR;
((DLG)m_pWnd)->Dispatch(S_ENDRETR);
error="Sessionended\r\n";
s.Format("quit%c%c",13,10);
Send((LPCSTR)s,s.GetLength());
Close();
}
}
}
}break;
caseDELE:
{
//删除剩余邮件
if(delMsg{
delMsg++;
s.Format("dele%d%c%c",delMsg,13,10);
Send((LPCSTR)s,s.GetLength());
}
else//如果已经删除完毕
{
((DLG)m_pWnd)->Dispatch(S_ENDRETR);
state=GOON;
error="Deletedallmessages\r\n";
s.Format("quit%c%c",13,10);
Send((LPCSTR)s,s.GetLength());
Close();
}
}
break;
caseGOON:
//默认
default:
((DLG)m_pWnd)->Dispatch(S_RECEIVE);
break;
}
}
voidCPop3:
:
Close()
{
CStringstr;
str.Format("quit%c%c",13,10);
Send((LPCSTR)str,str.GetLength());
((DLG)m_pWnd)->Dispatch(S_CLOSE);
state=FIRST;
CAsyncSocket:
:
Close();
error="Notconnectedtoserver\r\n";
}
CStringCPop3:
:
GetError()
{
returnerror;
}
intCPop3:
:
GetNumMsg()
{
returnnumMsg;
}
BOOLCChooseDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//TODO:
Addextrainitializationhere
CPop3Dlg*par;
par=(CPop3Dlg*)GetParent();//获得父窗体
for(inti=0;ipop3.GetRetrMsgNum();i++)
{
AddToList(par->pop3.GetMsgSubject(i));
}
ctlList.SetCurSel(0);
returnTRUE;
intCPop3:
:
GetSizeMsg()
{
returnsizeMsg;
}
intCPop3:
:
GetRetrMsgNum()
{
returnmsgs.size();
}
CStringCPop3:
:
GetMsg(inti)
{
returnmsgs[i].text;
}
CStringCPop3:
:
GetMsgSubject(inti)
{
intwhere=msgs[i].text.Find("Subject:
");
CStringret;
if(where!
=-1)
ReadLn(where,msgs[i].text,ret);
returnret;
}
voidCPop3:
:
DelAfterRead(BOOLdel)
{
delAfterRead=del;
}
CStringCPop3:
:
GetMsgBody(inti)
{
CStringret;
intwhere=msgs[i].text.Find("\r\n\r\n");
if(where!
=-1)
where+=4;
elsewhere=0;
ret=msgs[i].text.Right(msgs[i].text.GetLength()-where);
ret=ret.Left(ret.GetLength()-3);
returnret;
}
CStringCPop3:
:
GetMsgStuff(inti)
{
CStringret;
intwhere=msgs[i].text.Find("From:
");
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
where=msgs[i].text.Find("To:
");
if(where!
=-1)
{
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
}
where=msgs[i].text.Find("Date:
");
if(where!
=-1)
{
ReadLn(where,msgs[i].text,ret);
ret+="\r\n";
}
ret+=GetMsgSubject(i);
ret+="\r\n";
returnret;
}
voidCPop3:
:
ReadLn(intindex,CStringsrc,CString&dst)
{
CStringcomp;
comp=sr