资源描述
南京邮电大学通信与信息工程学院课程设计报告201 /201 学年 第二学期课程设计 实验报告模 块 名 称 TCP/IP网络通信程序设计专 业 学 生 班 级 学 生 学 号 学 生 姓 名 指 导 教 师 QT5.6环境下的源代码目 录题目1获取计算机的名称和IP地址11、设计内容12、设计分析论述及程序实现流程框图13、关键实现代码及注解24、程序运行测试与结果45、程序设计中遇到的问题及改进思路4题目2基本C/S模式的通信实验51、设计内容52、设计分析论述及程序实现流程框图53、关键实现代码及注解84、程序运行测试与结果215、程序设计中遇到的问题及改进思路23题目3简单的浏览器的实现241、设计内容242、设计分析论述及程序实现流程框图243、关键实现代码及注解254、程序运行测试与结果265、程序设计中遇到的问题及改进思路28题目4利用smtp协议发送邮件291、设计内容292、设计分析论述及程序实现流程框图293、关键实现代码及注解304、程序运行测试与结果375、程序设计中遇到的问题及改进思路38课程设计小节39附录4039题目1获取计算机的名称和IP地址1、设计内容获取计算机的名称和IP地址实验 编写程序实现下述功能:获取计算机的名称和IP地址2、设计分析论述及程序实现流程框图 Qt Creator是一个用于Qt开发的轻量级跨平台集成开发环境。Qt Creator可带来两大关键益处:提供首个专为支持跨平台开发而设计的集成开发环境 (IDE),并确保首次接触Qt框架的开发人员能迅速上手和操作。即使不开发Qt应用程序,Qt Creator也是一个简单易用且功能强大的IDE。Qt数据库中提供QtNetwork Module中的QHostInfo、QHostAddress、QNetworkInterface和QNetAddressEntry等类来查询网络参数。QNetworkInterface类提供了程序所运行的主机IP地址和网络接口信息的列表,在一个网络接口信息中,包含一个或多个IP地址,每一个IP地址又包含和它相关的子网掩码和广播地址。它们三者别封装在一个对象中QNetworkAddressEntry,网络接口信息也包含了硬件地址信息。1完成界面getHostInformation()函数获得主机信息slotDetail()函数网络接口信息运行出结果3、关键实现代码及注解1. 在NetworkInformation.pro文件中,添加QT += network2. 在头文件networkinformation.h中添加如下代码:#include #include public:void getHostInformation();public slots:void slotDetail();对QHostInfo、QNetworkInterface进行声明,添加槽函数。3. 在源文件networkinformation.cpp中添加代码。其中在构造函数的最后添加:getHostInformation(); /用于获得主机信息connect(detailBtn,SIGNAL(clicked(),this,SLOT(slotDetail();4. getHostInformation()函数用于获得主机信息。具体实现代码如下:void NetworkInformation:getHostInformation() QString localHostName = QHostInfo:localHostName();/获得本机主机名 LineEditLocalHostName-setText(localHostName); QHostInfo hostInfo = QHostInfo:fromName(localHostName);/根据主机名获得相关主机信息,包括IP地址等。QHostInfo:fromName()函数通过主机名查找IP地址信息。 QList listAddress = hostInfo.addresses();/获得主机的IP地址列表 if(!listAddress.isEmpty()/获得的主机IP地址列表可能为空。在不为空的情况下使用第一个IP地址。 LineEditAddress-setText(listAddress.first().toString(); 注释见上。25. slotDetail()函数获得与网络接口相关的信息,具体实现代码如下:void NetworkInformation:slotDetail()/获得与网络接口相关的信息 QString detail=; QList list=QNetworkInterface:allInterfaces();/QNetworkInterface类提供了一个主机IP地址和网络接口的列表 for(int i=0;ilist.count();i+) QNetworkInterface interface=list.at(i); detail=detail+u8设备:+interface.name()+n;/获得网络接口的名称 detail=detail+u8硬件地址:+interface.hardwareAddress()+n;/获得网络接口的硬件地址 QList entryList=interface.addressEntries(); /每个网络接口包括0个或多个IP地址,每个IP地址有选择性地与一个子网掩码和(或)一个广播地址相关联 /QNetworkAddressEntry类存储了被网络接口支持的一个IP地址,同时还包括与之相关的子网掩码和广播地址 for(int j=0;jentryList.count();j+) QNetworkAddressEntry entry=entryList.at(j); detail=detail+t+u8IP 地址:+entry.ip().toString()+n; detail=detail+t+u8子网掩码:+mask().toString()+n; detail=detail+t+u8广播地址:+entry.broadcast().toString()+n; QMessageBox:information(this,tr(Detail),detail);4、程序运行测试与结果 图1-1 获取本机网络信息 图1-2 获取本机详细网络信息5、程序设计中遇到的问题及改进思路1. “详细”这个按钮单击时,没有明显的痕迹,故后期添加了一些特效。将PushButton的属性checkable设置为真,则运行时鼠标单击一下,按钮的颜色会变淡,再单击一下又会变亮,它是以颜色的的深浅来提醒它的toggle的。菜单栏中的一个选项,一般是用trigger来发射信号。2报错出现“cannot find file main.pro”,原因是QT所使用的工程,目录树中出现汉字,空格等。题目2基本C/S模式的通信实验1、设计内容基本C/S模式的通信实验编写程序实现一个基于UDP 模式的通信程序和一个基于TCP 模式的通信程序。基本要求:能输入计算机的IP地址和端口号,能输入、发送文本信息和显示接受的文本信息。2、设计分析论述及程序实现流程框图一、基于UDP模式在UDP方式下,它是一个不可靠的,面向数据报的无连接协议。客户端并不与服务器建立连接,它只负责调用发送函数向服务器发出数据报。同样,服务器也不从客户端接收连接,只负责调用接收函数,等待来自某客户端的数据到达。Qt中通过QupSocket类实现UDP协议的编程。Socket简单地说,就是一个IP 地址加一个port端口。因为要传输数据,就要知道往哪个机子上传送,而IP 地址确定了一台主机,但是这台机子上可能运行着各种各样的网络程序,这时就要使用一个端口来指定UDP 程序。所以说,Socket 指明了数据报传输的路径。编写两个程序,一个用来发送数据报,叫做客户端;另一个用来接收数据报,叫做服务器端,均应用UDP 协议。这样也就构成了所谓的C/S(客户端/服务器)编程模型。首先做服务器端。先在头文件udpclient.h中声明需要的各种控件,完成对应源代码,从而先形成一个服务器的界面。然后在头文件udpclient.h中添加需要的槽函数,在源文件udpserver.cpp中添加声明,设置好端口参数(本程序设置为5555)并且创建QUdpSocket,使程序能够定向发送广播地址。接下来做客户端。同样先在头文件udpclient.h中声明需要的各种控件,完成对应源代码,从而形成一个客户端的界面。然后在构造函数中设置相对应的端口号参数(5555),定义CloseBtnClicked()和dataReceived()函数,最后实现客户端的功能。图2-1 UDP协议工作原理图2-2 UDP客户端与服务器之间的交互方式二、基于TCP模式1.图2-3 TCP协议工作原理2. 图2-4 TCP客户端与服务器间的交互时序3.图2-5 TCP文件传输结构3、关键实现代码及注解一、基于UDP模式服务器端:1.在UdpServer.pro中添加:QT += network2.在头文件udpserver.h中添加需要的槽函数:#include /Line11.12声明,为了在Line21-32添加槽函数#include public slots: void StartBtnClicked(); void timeout();private: QLabel *TimerLabel; QLineEdit *TextLineEdit; QPushButton *StartBtn; QVBoxLayout *mainLayout; int port; bool isStarted; QUdpSocket *udpSocket;QTimer *timer;3.在udpserver.cpp的槽函数中添加如下代码:connect(StartBtn,SIGNAL(clicked(),this,SLOT(StartBtnClicked(); port =6665;/设置UDP的端口号参数,服务器定时向此端口发送广播消息 isStarted=false; udpSocket = new QUdpSocket(this); timer = new QTimer(this);/创建一个QUdpSocket connect(timer,SIGNAL(timeout(),this,SLOT(timeout();/定时发送广播信息4. StartBtnClicked()函数的具体代码:void UdpServer:StartBtnClicked()/“开始”按钮函数的设定 if(!isStarted) StartBtn-setText(u8停止); timer-start(1000); isStarted =true; else StartBtn-setText(u8开始); isStarted = false; timer-stop(); 5.timeout()函数完成了向端口发送广播消息的功能:void UdpServer:timeout()/完成向端口发送广播信息的功能 QString msg = TextLineEdit-text(); int length=0; if(msg=) return; if(length=udpSocket-writeDatagram(msg.toLatin1(),msg.length(),QHostAddress:Broadcast,port)!=msg.length() return; /QHostAddress:Broadcast指定向广播地址发送客户端:1.在UdpClient.pro中加入代码:QT += network2.在udpclient.cpp的构造函数中添加代码:connect(CloseBtn,SIGNAL(clicked(),this,SLOT(CloseBtnClicked(); port =6665;/设置UDP的端口号参数,指定在此端口上监听数据 udpSocket = new QUdpSocket(this);/创建一个QUdpSocket connect(udpSocket,SIGNAL(readyRead(),this,SLOT(dataReceived(); /连接QIODevice的readyRead()信号。QUdpSocket也是一个I/O设备,从QIODevice继承而来,当有数据到达I/O设备时,发出readyRead()信号 bool result=udpSocket-bind(port);/绑定到指定端口上 if(!result) QMessageBox:information(this,tr(error),tr(udp socket create error!); return;3.定义CloseBtnClicked()函数:void UdpClient:CloseBtnClicked() close();4.定义dataReceived()函数:void UdpClient:dataReceived()/响应QUdpSocket的readyRead()信号,一旦UdpSocket对象中有数据可读时,即通过readyDatagram()方法将数据读出并显示 while(udpSocket-hasPendingDatagrams()/判断UdpSocket中是否有数据报可读,hasPendingDatagrams()方法在至少有一个数据报可读时返回true,否则返回false QByteArray datagram;/Line47-50实现了读取第一个数据报,pendingDatagramSize()可以获得第一个数据报长度 datagram.resize(udpSocket-pendingDatagramSize(); udpSocket-readDatagram(datagram.data(),datagram.size(); QString msg=datagram.data(); ReceiveTextEdit-insertPlainText(msg);/显示数据内容 二、基于TCP模式服务器端:1.头文件“tcpserver.h”中声明了需要的各种控件,TcpServer继承自Qdialog,实现了服务器端的对话框显示与控制。具体代码如下2:#include #include #include #include #include #include #include server.hclass TcpServer : public QDialog Q_OBJECTpublic: TcpServer(QWidget *parent = 0,Qt:WindowFlags f=0); TcpServer();private: QListWidget *ContentListWidget; QLabel *PortLabel; QLineEdit *PortLineEdit; QPushButton *CreateBtn; QGridLayout *mainLayout; int port; Server *server;2.在源文件“tcpserver.cpp”中,TcpServer类的构造函数主要实现窗体各控件的创建、布局等,其具体代码如下:#include tcpserver.hTcpServer:TcpServer(QWidget *parent,Qt:WindowFlags f) : QDialog(parent,f) setWindowTitle(tr(TCP Server); ContentListWidget = new QListWidget; PortLabel = new QLabel(u8端口:); PortLineEdit = new QLineEdit; CreateBtn = new QPushButton(u8创建聊天室); mainLayout = new QGridLayout(this); mainLayout-addWidget(ContentListWidget,0,0,1,2); mainLayout-addWidget(PortLabel,1,0); mainLayout-addWidget(PortLineEdit,1,1); mainLayout-addWidget(CreateBtn,2,0,1,2); port=5555; PortLineEdit-setText(QString:number(port); connect(CreateBtn,SIGNAL(clicked(),this,SLOT(slotCreateServer();3. 在工程“TcpServer.pro”中添加如下语句:QT += network4. 在工程“TcpServer.pro”中添加C+类文件“tcpclientsocket.h”及“tcpclientsocket.cpp”,TcpClientSocket继承自QTcpSocket,创建一个TCP套接字,以便在服务器端实现与客户端程序的通信。在源文件“tcpclientsocket.cpp”中,构造函数(TcpClientSocket)的内容如下(它指定了信号与槽的连接关系):#include tcpclientsocket.hTcpClientSocket:TcpClientSocket(QObject *parent)/指定了信号与槽的连接关系 connect(this,SIGNAL(readyRead(),this,SLOT(dataReceived(); connect(this,SIGNAL(disconnected(),this,SLOT(slotDisconnected();/disconnected()信号在断开连接时发出5. 在源文件“tcpclientsocket.cpp”中,dataReceived()函数的具体代码如下:void TcpClientSocket:dataReceived()/有数据到来时,触发dataReceived()函数,从套接字中将有效数据取出,然后发出updateClients()信号。 while(bytesAvailable()0) int length = bytesAvailable(); char buf1024; read(buf,length); QString msg=buf; emit updateClients(msg,length);/updateClients()信号是通知服务器向聊天室内的所有成员广播信息 6.在工程“TcpServer.pro”中添加C+类文件“server.h”及“server.cpp”,Server继承自QTcpServer,实现一个TCP协议的服务器。利用QTcpServer,开发着可以监听到指定端口的TCP连接。其具体代码如下:#include #include #include tcpclientsocket.h/包含TCP套接字class Server : public QTcpServer Q_OBJECT /添加宏(Q_OBJECT)是为了实现信号与槽的通信public: Server(QObject *parent=0,int port=0); QList tcpClientSocketList;/用来保存与每一个客户端连接的TcpClientSocketsignals: void updateServer(QString,int);public slots: void updateClients(QString,int); void slotDisconnected(int);protected: void incomingConnection(int socketDescriptor);7.在源文件“server.cpp”中,构造函数(Server)的具体内容如下:#include server.hServer:Server(QObject *parent,int port) :QTcpServer(parent) listen(QHostAddress:Any,port);/在指定的端口对任意地址进行监听8. 在源文件“server.cpp”中,当出现一个新的连接时,QTcpServer会立即触发incomingConnection()函数,参数socketDescriptor指定了连接的Socket描述符,其具体代码如下:void Server:incomingConnection(int socketDescriptor)/出现一个新的连接时,QTcpServer触发incomingConnection()函数 TcpClientSocket *tcpClientSocket=new TcpClientSocket(this);/创建一个新的TcpClientSocket与客户端通信 connect(tcpClientSocket,SIGNAL(updateClients(QString,int),this,SLOT(updateClients(QString,int);/连接TcpClientSocket的updateClients信号 connect(tcpClientSocket,SIGNAL(disconnected(int),this,SLOT(slotDisconnected(int);/连接TcpClientSocket的disconnected信号 tcpClientSocket-setSocketDescriptor(socketDescriptor);/将新创建的TcpClientSocket的套接字描述符指定为参数socketDescriptor tcpClientSocketList.append(tcpClientSocket);/将tcpClientSocketList加入客户端套接字列表以便管理9. 在源文件“server.cpp”中,updateClients()函数将任意客户端发来的信息进行广播,保证聊天室的所有客户均能看到其他人的发言。其具体代码如下:void Server:updateClients(QString msg,int length)/将任意客户端发来的信息进行广播,保证聊天室的所有客户均能看到其他人的发言 emit updateServer(msg,length); for(int i=0;iwrite(msg.toLatin1(),length)!=length) continue; 10. 在源文件“tcpserver.cpp”中,槽函数slotCreateServer()用于创建一个TCP服务器,具体内容如下:void TcpServer:slotCreateServer()/创建一个TCP服务器 server = new Server(this,port);/创建一个Server对象 connect(server,SIGNAL(updateServer(QString,int),this,SLOT(updateServer(QString,int);/将Server对象的updateServer()信号与相应的槽函数进行连接 CreateBtn-setEnabled(false);客户端:1.源文件“tcpclient.cpp”的具体代码如下:#include tcpclient.h#include #include TcpClient:TcpClient(QWidget *parent,Qt:WindowFlags f) : QDialog(parent,f) setWindowTitle(tr(TCP Client); contentListWidget = new QListWidget; sendLineEdit = new QLineEdit; sendBtn = new QPushButton(u8发送); userNameLabel = new QLabel(u8用户名:); userNameLineEdit = new QLineEdit; serverIPLabel = new QLabel(u8服务器地址:); serverIPLineEdit = new QLineEdit; portLabel = new QLabel(u8端口:); portLineEdit = new QLineEdit; enterBtn= new QPushButton(u8进入聊天室); mainLayout = new QGridLayout(this); mainLayout-addWidget(contentListWidget,0,0,1,2); mainLayout-addWidget(sendLineEdit,1,0); mainLayout-addWidget(sendBtn,1,1); mainLayout-addWidget(userNameLabel,2,0); mainLayout-addWidget(userNameLineEdit,2,1); mainLayout-addWidget(serverIPLabel,3,0); mainLayout-addWidget(serverIPLineEdit,3,1); mainLayout-addWidget(portLabel,4,0); mainLayout-addWidget(portLineEdit,4,1); mainLayout-addWidget(enterBtn,5,0,1,2);2.在客户端工程文件“TcpClient.pro”中添加如下语句:QT += network3.在源文件“tcpclient.cpp”的构造函数中添加如下代码:status = false; port = 5555; /随意设置端口号 portLineEdit-setText(QString:number(port); serverIP =new QHostAddress(); connect(enterBtn,SIGNAL(clicked(),this,SLOT(slotEnter(); connect(sendBtn,SIGNAL(clicked(),this,SLOT(slotSend(); sendBtn-setEnabled(false);以上代码中,槽函数slotEnter()实现了进入和离开聊天室的功能。具体代码如下:void TcpClient:slotEnter()/实现了进入和离开聊天室的功能 if(!status) QString ip = serverIPLineEdit-text(); if(!serverIP-setAddress(ip) QMessageBox:information(this,tr(error),tr(server ip address error!); return; if(userNameLineEdit-text()=) QMessageBox:information(this,tr(error),tr(User name error!); return; userName=userNameLineEdit-text(); tcpSocket = new QTcpSocket(this); connect(tcpSocket,SIGNAL(connected(),this,SLOT(slotConnected(); connect(tcpSocket,SIGNAL(disconnected(),this,SLOT(slotDisconnected(); connect(tcpSocket,SIGNAL(readyRead(),this,SLOT(dataReceived(); tcpSocket-connectToHost(*serverIP,port); status=true; else int length=0; QString msg=userName+tr(:Leave Chat Room); if(length=tcpSocket-write(msg.toLatin1(),msg.length()!=msg. length() return; tcpSocket-disconnectFromHost(); status=false; 4. 槽函数slotConnected():void TcpClient:slotConnected()/槽函数slotConnected()为connected()信号的响应槽,当与服务器连接成功后,客户端构造一条进入聊天室的消息,并通知服务器 sendBtn-setEnabled(true); enterBtn-setText(u8离开); int length=0; QString msg=userName+tr(:Enter Chat Room); if(length=tcpSocket-write(msg.toLatin1(),msg.length()!=msg.length() return; 5.源文件“tcpclient.cpp”中的dataReceived()函数:void TcpClient:dataReceived()/有数据到来时,触发此函数,从套接字中将有效数据取出并显示 while(tcpSocket-bytesAvailable()0) QByteArray datagram; datagram.resize(tcpSocket-bytesAvailable(); tcpSocket-read(datagram.data(),datagram.size(); QString msg=datagram.data(); contentListWidget-addItem(msg.left(datagram.size(); 4、程序运行测试与结果一、基于UDP模式图2-6 服务器端窗口图2-7 客户端窗口说明:打开服务器端口,输入字符(最好是英文字符),同时打开客户端。在服务器端点击“开始”按钮,便以时钟间隔向客户端发送输入的字符,同时显示在客户端窗口上,直到点击“停止”按钮,才终止发送。二、基于TCP模式图2-8服务器端窗口图2-9 客户端窗口说明: 操作方式类似于UDP。点击发送即可进行客户端和服务器之间的对话。5、程序设计中遇到的问题及改进思路1. 出现field m_createDate has incomplete type错误。由于只在头文件中加了class声明,如class QDateTime,在cpp文件中也使用#include 将该类引入,但由于使用QDateTime m_createDate;方式为创建了QDateTime对象,但由于只是对QDateTime类进行了声明而隐藏了类的实现,此时编译时不知道QDateTime的完成实现所以无法创建QDateTime对象。解决方法是在头文件中使用#include 方式替换class QDateTime。2出现“QApplication: No such file or directory”报错。则检查工程文件中*.pro中是否有“QT += widgets”,若没有,则需要在工程文件*.pro下增加一条:“QT += widgets”,则问题就可以解决了。3出现“error: tr was not declared in this scope”,tr这个函数是QObject对象中的静态成员函数,因此使用的时候,如果不是用类来写的话,就会报这个错误,只需要在tr函数前加上“QObject:”,如:“QObject:tr(a button)”这样既可。题目3简单的浏览器的实现1、设计内容简单的浏览器的实现:设计一个简单的浏览器。基本要求:在菜单项或工具条实现打开一个新的网页指定的功能。提高要求:在菜单项或工具条实现下述功能之一:清除自动密码历史记录。浏览器地址栏历史地址的清除。清空临时目录。2、设计分析论述及程序实现流程框图Qt5开始,应用层的编程使用QNetworkRequest、QNetworkReply和QNetworkAccessManager这几个高层次的类。其中,网络请求由QnetworkRequest类来表示,作为与请求有关的信息的统一容器,在创建请求对象时指定的URL决定了请求使用的协议,目前支持HTTP、FTP和本地文件URLs的上传和下载;QnetworkAccessManager类用于协调网络操作,每当一个请求创建后,该类用来调度它,并发射信号来报告进度;而对于网络请求的应答则使用QnetworkReply类表示,它会在请求被完成调度时由QnetworkAccessManager创建。新建Qt Gui应用,名称为“myHTTP”,类名为“MainWindow”。完成后进入设计模式,即打开ui界面设计,向界面上拖入一个Text Browser窗口,然后在头文件和源文件中加入相应代码。图3-1 浏览器与服务器的连接过程图3-2 ui界面的设计3、关键实现代码及注解1.进入“mainwindow.h”文件,首先添加类的前置声明: class QNetworkReply; /Line5.6为类的前置声明class QNetworkAccessManager;2.添加一个私有对象定义:QNetworkAccessManager *manager;3.添加一个私有槽的声明:private slots:void replyFinished(QNetworkReply *);/此私有槽声明上面的私有对象4.在“mainwindow.cpp”文件中添加头文件:#include 然后在构造函数中添加如下代码:manager = new QNetworkAccessManager(this);/首先创建一个QNetworkAccessManager类的实例,用来发送网络请求和接收应答 connect(manager,SIGNAL(finished(QNetworkReply*),this,SLOT(replyFinished(QNetworkReply*);/关联管理器的finished()信号和自定义的槽,每当网络应答结束时都会发射这个信号manager-get(QNetworkRequest(QUrl(http:/);/使用get()函数发送一个网络请求,请求使用QNetworkRequest类表示,get()函数返回一个QNetworkReply类对象5.添加槽的定义:void MainWindow:replyFinished(QNetworkReply *reply) QString all = reply-readAll(); ui-textBrowser-setText(all); reply-deleteLater(); 因为QNetworkReply继承自QIODevice类,所以可以像操作一般的I/O设备一样操作该类。这里使用了readAll()函数来读取所有的应答数据。在完成数据的读取后,需要使用deleteLater()删除reply对象。4、程序运行测试与结果 先实现网页上文字链接的显示。如图3-3.图3-3然后查阅网上资料,完成完整的浏览器设计。可以输入网址浏览网页,可以将网页添加到收藏夹,可以生成浏览历史记录。如图3-4,3-5.图3-4图3-55、程序设计中遇到的问题及改进思路1. 当使用tr进行语言国际化时,有可能会出现错误:error : tr was not declared in this scope。解决方法:在程序中加入#include,并使用QObject:tr();2. 编译时遇到“No rule to make target xxx.cpp, needed by debug/xxx.o. Stop.”的问题,出现该问题的原因为,在.pro文件中包含了某.cpp文件和.h文件,但是在项目中可能因为该文件未被使用,在本地直接删掉了该文件,而.pro文件中还包含了这两个文件的引用,此时编译就会出现以上问题。解决办法是在.pro文件中删除“xxx.cpp”和“xxx.h”的引用即可。题目4利用smtp协议发送邮件1、设计内容利用smtp协议发送邮件基本要求:能发送内容为文本信息的邮件。提高要求:能发送带有附件信息的邮件。2、设计分析论述及程序实现流程框图SMTP称为简单邮件传输协议(Simple Mail Transfer Protocal),目标是向用户提供高效、可靠的邮件传输。它的一个重要特点是它能够在传送中接力传送邮件,即邮件可以通过不同网络上的主机接力式传送。通常它工作在两种情况下:一是邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器。SMTP是一个请求/响应协议,它监听25号端口,用于接收用户的Mail请求,并与远端Mail服务器建立SMTP连接。SMTP通常有两种工作模式。发送SMTP和接收SMTP。具体工作方式为:发送SMTP在接收到用户的邮件请求后,判断此邮件是否为本地邮件,若是直接投送到用户的邮箱,否则向DNS查询远端邮件服务器的MX记录,并建立与远端接收SMTP之间的一个双向传送通道,此后SMTP命令由发送SMTP发出,由接收SMTP接收,而应答则反方向传送。一旦传送通道建立,SMTP发送者发送MAIL命令指明邮件发送者。如果SMTP接收者可以接收邮件则返回OK应答。SMTP发送者再发出RCPT命令确认邮件是否接收到。如果SMTP接收者接收,则返回OK应答;如果不能接收到,则发出拒绝接收应答(但不中止整个邮件操作),双方将如此反复多次。当接收者收到全部邮件后会接收到特别的序列,入伏哦接收者成功处理了邮件,则返回OK应答。SMTP的连接和发送过程大致如下:(1)建立TCP连接;(2)客户端发送HELO命令以标识发件人自己的身份,然后客户端发送MAIL命令。服务器端正希望以OK作为响应,表明准备接收;(3)客户端发送RCPT命令,以标识该电子邮件的计划接收人,可以有多个RCPT行。服务器端则表示是否愿意为收件人接收邮件;(4)协商结束,发送邮件,用命令DATA发送;(5)以.表示结束输入内容一起发送出去;(6)结束此次发送,用QUIT命令退出。3、关键实现代码及注解1.在SMTP.pro文件中加入如下代码,依次读取工程目录中其他文件夹的内容:SOURCES += src/emailaddress.cpp src/mimeattachment.cpp src/mimefile.cpp src/mimehtml.cpp src/mimeinlinefile.cpp src/mimemessage.cpp src/mimepart.cpp src/mimetext.cpp src/smtpclient.cpp src/quotedprintable.cpp src/mimemultipart.cpp src/mimecontentformatter.cpp src/main.cpp src/sendemail.cppHEADERS += src/emailaddress.h src/mimeattachment.h src/mim
展开阅读全文