indy的ftp控件idftp也有bug

公司里有一个服务使用ftp方式做数据传输,于是在服务程序中使用indy的ftp控件做数据传输,一段时间的运行发现在传输过程中由于某种不知道原因情况下的网络掉线会导致程序会死翘翘,仔细分析了程序的逻辑,没有发现问题,根据记录下的日志文件,发现死翘翘前在做ftp文件传输处理,但是对其的try except end异常保护块没有记录下异常,遂开始怀疑使用的idftp控件问题,因为以前使用idTCPClient的时侯也碰到过问题。

使用google搜索关键字idftp bug 发现 http://groups.google.com.hk/group/borland.public.delphi.internet.winsock/browse_thread/thread/7b65058aa344137f/070b497000a0ea46?fwc=1 有讲到这个问题,是由于idftp在数据端口传输数据时忘记了设置连接的ReadTimeout 属性值造成。

原文作者在 interalGet函数中打了一下补丁,不过分析了一下,发现原文作者只打了interalGet中的主动传输方式部分代码,被动(passive)传输方式以及interalPut函数中也存在同样问题的代码没有打补丁。
仔细看了一下代码,发现只要给InitDataChannel函数打下补丁就可,他在interalGet和interalPut函数中的主被动方式中都有使用。

  1. procedure TIdFTP.InitDataChannel;
  2. begin
  3.   FDataChannel.SendBufferSize := SendBufferSize;
  4.   FDataChannel.RecvBufferSize := RecvBufferSize;
  5.   FDataChannel.OnWork := OnWork;
  6.   FDataChannel.OnWorkBegin := OnWorkBegin;
  7.   FDataChannel.OnWorkEnd := OnWorkEnd;
  8.  
  9.   // 添加的代码行 added line to fix the readtimeout bug
  10.   FDataChannel.ReadTimeout := Self.ReadTimeOut;
  11. end;

———–
到此程序的分析修改就告一段落了,接下来就要让程序24×7不停的运行,以观察看是否还是否有类似问题发生了。

Popularity: 5% [?]

Related

在Delphi中使用indy SMTP发送gmail邮件

在Delphi中发送email很简单,发送ssl方式的gmail邮件也很简单,只要在使用的idSMTP上附加一个TIdSSLIOHandlerSocket 就可以了。
使用控件

  1. procedure sendMail(sToMail, sSubject, sContent: String);
  2. var
  3.     SMTP: TIdSMTP;
  4.     MailMessage: TIdMessage;
  5.     SSLSocket: TIdSSLIOHandlerSocket;
  6. begin
  7.   SMTP        := TIdSMTP.Create(nil);
  8.   SSLSocket := TIdSSLIOHandlerSocket.Create(nil);
  9.   MailMessage:= TIdMessage.Create(nil);
  10.  
  11.   SMTP.IOHandler := SSLSocket;
  12.   SMTP.Port   := 465;
  13.   SMTP.Host := 'smtp.gmail.com';
  14.   SMTP.AuthenticationType  := atLogin;
  15.  
  16.   smtp.UserName     := 'SunnyYu2000';
  17.   smtp.Password      := 'xxxxxx';
  18.  
  19.   // 设置邮件的信息
  20.   MailMessage.From.Address := 'SunnyYu2000@gmail.com';
  21.   MailMessage.Recipients.EMailAddresses := sToMail;
  22.   MailMessage.Subject := sSubject;  
  23.   MailMessage.Body.Text := sContent;
  24.  
  25.   //发送邮件
  26.   try
  27.     try
  28.       SMTP.Connect(1000);
  29.       SMTP.Send(MailMessage);
  30.       ShowMessage('发送成功');
  31.     except on E:Exception do
  32.       ShowMessage('发送失败: ' + E.Message);
  33.     end;
  34.   finally
  35.     if SMTP.Connected then
  36.       SMTP.Disconnect;
  37.   end;
  38.  
  39.   MailMessage.Free;
  40.   SSLSocket.Free;
  41.   SMTP.Free;
  42. end;

编译后需要SSL动态库支持,支持库可以到Indy网站上下载到。
如果需要发送附件,可以再发送前添加如下类似代码

  1.    // 添加邮件的附件
  2.    TIdAttachment.Create(MailMessage.MessageParts, sAttachmentFileName);

————–
Indy需要的SSL支持dll下载地址 http://www.indyproject.org/Sockets/SSL.EN.aspx

Popularity: 5% [?]

Related

使用indy解析http协议的multipart上传数据

MMS彩信的数据附在Soap包后面,在正常解析soap的xml文件外,还需要对使用multipart/related编码上传的数据做解析处理,在indy中提供了解码类。

处理解码时,需要TIdMessageDecoderMIME负责实际的解码, TIdMIMEBoundary从头信息中做边界信息查找。
解码函数

  1. procedure DecodeFormData(const sHeader: String; ASourceStream:TStream; sSavePath: String);
  2. var
  3.   bEnd : Boolean;
  4.   sTmp: String;
  5.   Decoder: TIdMessageDecoderMIME;
  6.   ds: TStream;
  7. begin
  8.   bEnd := False;
  9.   Decoder := TIdMessageDecoderMIME.Create(nil);
  10.  
  11.   try
  12.     // 设置附件的边界
  13.     Decoder.MIMEBoundary := TIdMIMEBoundary.FindBoundary(sHeader);
  14.     Decoder.SourceStream := ASourceStream;
  15.     Decoder.ReadLn;
  16.    
  17.     repeat
  18.        Decoder.ReadHeader;  // 读入分块的Header信息
  19.        case Decoder.PartType of
  20.            mcptUnknown:
  21.                raise Exception.Create('Unknown form data detected');
  22.            mcptText:
  23.                begin
  24.                   sTmp := Decoder.Headers.Values['Content-Type'];  // 获取ContentType
  25.                   ds := TMemoryStream.Create;
  26.                   try
  27.                      Decoder := Decoder.ReadBody(ds,bEnd);
  28.                      // 如果取的数据仍然是由多块组成,则进行递归处理
  29.                      if AnsiSameText(Fetch(Tmp, ';'),'multipart/mixed') then
  30.                         DecodeFormData(sTmp, ds, sSavePath)
  31.                      else
  32.                         // 根据需要使用Dest的数据
  33.                   finally
  34.                      FreeAndNil(ds);
  35.                   end;//try
  36.                end; //  mcptText
  37.  
  38.            mcptAttachment:
  39.                begin
  40.                   // 处理附件的文件名
  41.                   sTmp := ExtractFileName(Decoder.FileName);
  42.                   if sTmp <> '' then
  43.                      sTmp := sSavePath + sTmp
  44.                   else
  45.                      sTmp := MakeTempFilename(sSavePath);
  46.  
  47.                   ds := TFileStream.Create(sTmp, fmCreate);
  48.                   try
  49.                       Decoder := Decoder.ReadBody(ds,bEnd);
  50.                   finally
  51.                       FreeAndNil(ds);
  52.                   end;//try
  53.              end;  // mcptAttachment
  54.         end; // case
  55.     until (Decoder = nil) or bEnd;
  56.   finally
  57.     FreeAndNil(Decoder);
  58.   end;//try
  59. end;

使用OnCreatePostStream 创建用来接受HttpPost数据的Stream

  1. CreatePostStream(ASender: TIdPeerThread; var VPostStream: TStream);
  2. begin
  3.    VPostStream := TMemoryStream.Create;
  4. end;

最后在OnCommandGet中做解析处理

  1. OnCommandGet(ASender: TIdPeerThread; ARequestInfo: TIdHttpRequestInfo; AResponseInfo: TIdHttpResponseInfo);
  2. var
  3.    sContentType : String
  4. begin
  5.    sContentType := ARequestInfo.ContentType;
  6.  
  7.    if AnsiSameText(Fetch(S, ';'), 'multipart') then begin
  8.         DecodeFormData(sContentType, ARequestInfo.PostStream, 'c:temp');
  9.    end else
  10.             // 根据需要对请求数据做处理…
  11. end;

Popularity: 5% [?]

Related