⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 091401_05.htm

📁 对于学习很有帮助
💻 HTM
字号:
<html>

<head>
<link REL="stylesheet" HREF="/style.css" TYPE="text/css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>计算机世界日报:
Email 服务器的简单实现
</title>
<!--***********-->
</head>

<body bgcolor="#FFFFFF" >














<p><br>
<font color="#b904e8"><b><em><a href="class.htm">返回</a></em></b></font>
<center>
<font color="#0000c0"><h2>
Email 服务器的简单实现
</h2></font>
<h3>
湖南艾邦信息技术有限公司  
<br>李岳梅
</h3>
</center>
<p><font color="#ffffff">----</font>

   贵刊1999年7月26日《编程技巧》栏目刊登的《监视POP3信箱》一文介绍了直接调用WinSock函数来进行POP3网络通信从而监视有无新邮件的方法。但我们知道从Delphi 3 开始,它自带的控件中有基于Internet开发的控件。如果我们充分利用这些控件开发Internet程序则可以简化编程工作,提高效率。鉴于目前POP3客户端的软件的种类繁多,(如Outlook Express,Foxmail 以及Web 方式下的各免费邮局),而服务器端(除Unix Email系统)很少公开原代码,下面我就向大家着重介绍一下利用 Delphi 4中Internet控件组的TClientSocket 和TServerSocket 控件来实现 Email POP3服务器端。如果您理解了Email POP3服务器的构造,相信也可以依葫芦画瓢写出Email SMTP服务器程序。在此基础上加入多线程技术使服务器能同时处理多个客户的连接请求,您就可以轻松地实现一个简单的Email服务器了。
<p><font color="#ffffff">----</font>
<b>一. 设计思路</b>
<p><font color="#ffffff">----</font>
    Email 系统采用C/S 结构。当用户想发送邮件时或收取邮件时在客户机上运行任意一个客户端程序,如Foxmail。在菜单’工具->选项’的邮件服务器里填上运行我们服务器程序的主机名。服务器主机24小时一直运行我们的服务器端程序,SMTP和POP3服务器程序分别在25端口和110端口侦听连接请求。当用户发信时,首先客户端会与服务器端建立Socket连接。然后开始一应一答的Client/Server间的通信。发信和收信时建立连接后服务器端分别要发送一个’250 OK’ 和’+OK pop3 server is ready ’的应答。客户端收到此应答后开始发送SMTP或POP3命令。POP3通信时一般最开始的命令是’user ‘和’pass’或’ apop’用以进行身份验证。注意由于POP3会话有3个状态,某些命令只在某特定状态下有效。当用户进行完所有的操作后发送一个’quit’命令。服务器端收到此命令即终止此次socket连接并继续侦听其他的连接请求。注意:POP3通信时客户端在Transaction状态下’quit’则进入update状态。如果从Authorization状态下’quit’则终止通信,而不进入Update状态。如果客户端不通过’quit’命令终止连接,POP3会话不会进入Update状态。而只有在Update状态下收到’quit’命令后服务器才会在断连前把标志为已删的邮件进行物理删除。
<p><font color="#ffffff">----</font>
<b>二. 代码实现(以POP3为例)</b>
<p><font color="#ffffff">----</font>
自定义TPOP类的描述:
<pre>
 SessionState = ( Init,Authorization, Transaction,Update);
 TPop=class (TComponent)
  public
     UserName:string;//Email帐户名
     PassWord:string; //Email口令
     ReceText:Pchar;  //server端收到的字符串
     PopState:SessionState;  
//pop状态:
init or authorization or transaction  or update
     MsgCount:integer; //邮件总数
     SizeCount:integer;  //邮件总大小
     ReplyString:string;//服务器端发送的应答信息
     DeleIndex:byte;//用户要删的邮件序号
     ListIndex:byte;//list方法 的参数:
用户要列出的序号为listindex的邮件信息
     RetrIndex:byte;//retr方法的参数:
用户要取序号为retrindex的邮件
     TopIndex:byte; //top方法的参数
     QuitFlag:boolean;//用户如果通过quit命断连则此变量为true;
反之(此时要把f_dele都置回0)
     OldMsgCount:integer;//旧邮件数:Last 命令返回
     //邮件头的各个域 
     HMsgId:string;
     HReplyTo:string;
     HDate:string;
     HFrom:string;
     HTo:string;
     HSubject:string;
     HMIME_Ver:real;
     HContent_Type:string;
     HContent_Transfer_Encoding:string;
     HText:string;
    //所有POP3服务器必须支持的命令
    procedure user;
    function pass:boolean;
    procedure stat;
    procedure dele;
    procedure list;
    procedure retr;
    procedure noop;
    procedure rset;
    procedure aquit;
    procedure tquit;
    //扩展的可选择实现的POP3 命令
   procedure top;
   procedure last;
   procedure apop;
   procedure uidl;
   end;
</pre>
<p><font color="#ffffff">----</font>
1. 建立连接
<p><font color="#ffffff">----</font>
我们可以看到利用了Tclientsocket后客户端请求建立连接只需下面的代码。
<pre>
with ClientSocket do
      begin
        Host := Server;
        Active := True;
      end;
</pre>
<p><font color="#ffffff">----</font>
服务器端利用TserverSocket,一直在侦听110端口,若客户端有连接请求,则ServerSocketAccept事件会被激活,建立起连接。
<pre>
procedure TMyForm.ServerSocketAccept(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   Statusbar1.Panels[0].Text :=
   '连接到 ' + Socket.RemoteAddress;
  //pop对象初始化
  pop:=TPop.Create(nil);
  pop.PopState:=init;
  pop.LoginResult:=false;
  pop.QuitFlag:=false;
  ServerSocket.Socket.Connections[0]
  .sendtext('+OK ibonc pop3 server is ready'+crlf);

end;
</pre>
<p><font color="#ffffff">----</font>
2. 通信
<p><font color="#ffffff">----</font>
服务器端收到客户端发来的信息,则会激活ServerSocketClientRead事件,通过ServerSocket的Socket.ReceiveText可以得到信息的内容。
<pre>
procedure TMyForm.ServerSocketClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var temp_command :string; 
//存放接收到的命令行,并做去crlf的处理
begin
 temp_command:=Socket.ReceiveText;
 //to remove the crlf in command line
 temp_command:=trim(copy(temp_command,1,
pos(crlf,temp_command)-1));   
 pop.ReceText:=pchar(temp_command);
 if  pop.popstate=init then
    if  strLIComp(pop.ReceText,'user ',5)=0 then
       pop.user
    else
       ServerSocket.Socket.Connections[0]
.sendtext('-ERR user name please')
 else if pop.popstate=authorization then
    begin
         if strLIComp(pop.ReceText,'pass ',5)=0 then
               pop.pass 
         else if strIComp(pop.ReceText,'quit')=0  then
               pop.aquit
             else
               ServerSocket.Socket.Connections[0]
.sendtext('-ERR pass word please');
    end
 else if pop.popstate=transaction then
     begin
          if  strIComp(pop.ReceText,'stat')=0  then
              pop.stat   
          else if strLIComp(pop.ReceText,'dele ',5)=0 then
              pop.dele
          else if strLIComp(pop.ReceText,'list',4)=0 then
              pop.list
          else if strLIComp(pop.ReceText,'retr ',5)=0 then
              pop.retr
          else if strIComp(pop.ReceText,'noop')=0 then
              pop.noop
          else if strIComp(pop.ReceText,'rset')=0 then
              pop.rset
          else if strIComp(pop.ReceText,'quit')=0 then
              pop.tquit
          else if strIComp(pop.ReceText,'last')=0 then
              pop.last
          else if strLIComp(pop.ReceText, 'apop ',5)=0 then
              pop.apop
          else if strLIComp(pop.ReceText, 'uidl ',5)=0 then
              pop.uidl
          else
              ServerSocket.socket.connections[0]
.sendtext('-ERR no such command yet'+crlf);
          end
end;
</pre>
<p><font color="#ffffff">----</font>
3. 关闭连接
<pre>
   procedure TMyForm.ServerSocket
ClientDisconnect(Sender: TObject;
        Socket: TCustomWinSocket);
   begin
     ServerSocket.Active := False;
     //如果client端没有通过quit 命令断连,
     则在断连时要把那些f_dele置为0
     if pop.QuitFlag=False then
       begin
         MyForm.query11.Close;
         MyForm.query11.Params[0].Asstring:=pop.UserName;
         MyForm.query11.prepare;
         MyForm.query11.execsql;
       end;
   end;
</pre>
<p><font color="#ffffff">----</font>
<b>三. 结语</b>
<p><font color="#ffffff">----</font>
由于Email系统与数据库表结构的紧密联系,笔者没有写出各POP3命令的具体实现。相信读者在认真阅读了RFC1939之后不难写出实现函数。现在就动手为你的公司写一个自己的Email服务器吧!



 



<p align="right"><small><em>中国计算机世界出版服务公司版权所有</em></small> 
<br>
</p>
</body>
</html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -