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: 6% [?]

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: 6% [?]

Related

网关发送彩信Nokia手机不能显示出smil文件内容问题解决

使用自己写的ParlayX2.0接口发送发送联通的MMS彩信,几个测试的手机除了Nokia手机接收时不能显示出smil文件内容(提示要通过 对象 菜单查看彩信附件内容)其他都基本都接收显示正常,网上查找了一些资料,说是对某些手机发送数据包时要添加附件的头信息 Content-Location 值,补上发送,仍然不行,联系厂商 华为,抓了一个实际通信的数据包,对比发现我程序中发送的数据包中对附件的 Content-Type 头信息中缺少 name 的值指定,修改一下程序,在Content-Type头信息中添加上该值信息,再次发送,手机能够正常显示smil文件内容。

补一下发送的附件头信息

Content-Type:text/plain;charset=”UTF-8″;name=”0_0.txt”
Content-ID:<0_0.txt>
Content-Location:0_0.txt

Popularity: 5% [?]

Random Posts

联通VAC定制包解析userIdType和updateType数据碰到的一个问题解决

因为没有使用java平台,也就没有使用建议的axis对提供的wsdl文件做处理,所有关于数据包的解析只能自己写程序做解析处理。
华为提供的vac请求样例包request.xml

  1. <soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soap="http://soap.bossagent.vac.unicom.com">
  2.    <soapenv:Header/>
  3.    <soapenv:Body>
  4.       <soap:orderRelationUpdateNotify soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  5.          <orderRelationUpdateNotifyRequest xsi:type="req:OrderRelationUpdateNotifyRequest" xmlns:req="http://req.sync.soap.bossagent.vac.unicom.com">
  6.             <recordSequenceId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">11</recordSequenceId>
  7.             <userIdType xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</userIdType>
  8.             <userId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</userId>
  9.             <serviceType xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</serviceType>
  10.             <spId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</spId>
  11.             <productId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">2</productId>
  12.             <updateType xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">3</updateType>
  13.             <updateTime xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">44444444</updateTime>
  14.             <updateDesc xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">444</updateDesc>
  15.             <linkId xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">44</linkId>
  16.             <content xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">?</content>
  17.             <effectiveDate xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">333333</effectiveDate>
  18.             <expireDate xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">2222222</expireDate>
  19.             <time_stamp xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">3333</time_stamp>
  20.             <encodeStr xsi:type="soapenc:string" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">111gg</encodeStr>
  21.          </orderRelationUpdateNotifyRequest>
  22.       </soap:orderRelationUpdateNotify>
  23.    </soapenv:Body>
  24. </soapenv:Envelope>

实际在网络上收到的数据包

  1. <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  2.  <soapenv:Body>
  3.   <ns1:orderRelationUpdateNotify soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://soap.bossagent.vac.unicom.com">
  4.    <orderRelationUpdateNotifyRequest href="#id0"/>
  5.   </ns1:orderRelationUpdateNotify>
  6.   <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="ns2:OrderRelationUpdateNotifyRequest" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns2="http://req.sync.soap.bossagent.vac.unicom.com">
  7.    <recordSequenceId xsi:type="soapenc:string">200903181622360043</recordSequenceId>
  8.    <userIdType href="#id1"/>
  9.    <userId xsi:type="soapenc:string">8613004849965</userId>
  10.    <serviceType xsi:type="soapenc:string">5</serviceType>
  11.    <spId xsi:type="soapenc:string">90000001</spId>
  12.    <productId xsi:type="soapenc:string">050002</productId>
  13.    <updateType href="#id2"/>
  14.    <updateTime xsi:type="soapenc:string">20090313110400</updateTime>
  15.    <updateDesc xsi:type="soapenc:string"></updateDesc>
  16.    <linkId xsi:type="soapenc:string"></linkId>
  17.    <content xsi:type="soapenc:string"></content>
  18.    <effectiveDate xsi:type="soapenc:string">20080301000000</effectiveDate>
  19.    <expireDate xsi:type="soapenc:string">20100301000000</expireDate>
  20.    <time_stamp xsi:type="soapenc:string">0318162236</time_stamp>
  21.    <encodeStr xsi:type="soapenc:string"></encodeStr>
  22.   </multiRef>
  23.   <multiRef id="id2" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</multiRef>
  24.   <multiRef id="id1" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="soapenc:int" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">1</multiRef>
  25.  </soapenv:Body>
  26. </soapenv:Envelope>

通过对数据包的分析,可以看到在实际包里面,采用了multiRef方式,对userIdType和updateType数据的值使用了href引用,这样在分析数据包时,就同时要根据节点的href属性值来判断处理所引用的值节点,然后再遍历multiRef的节点找匹配id属性值的,从而找出正确的值所在。

——-
虽然现在解析正确了,但是没有使用标准的xml开发包工具开发,缺少开发包所做的类型验证,数据包还原等处理,如果以后接口数据格式有发生变化还是要再次进行解析代码的修改处理,不过不想只为了一个xml解析目的就为服务器添加上java的一堆环境和东西,只好先忍受着自己手工分析xml数据吧。

Popularity: 5% [?]

Random Posts

IdHttp访问返回非2XX代码的地址后Response.Stream中无数据问题解决

直接使用IdHttp编写使用WebService方式交互数据的MMS客户端,发现在正常Post数据返回200错误代码时,Response中包含Xml Soap的数据包,但是当服务端返回Http 500这样有错误代码时,Response中没有数据。

是服务端真的没有返回数据吗?使用转包工具抓了一下数据包,发现服务器端在返回 Http 500错误代码后,仍然是返回了包含错误信息的xml soap数据包的。出现这样的情况应该是IdHttp在接收数据时出错。

打开idHttp文件分析了一下,发现其在 ProcessResponse 函数中存在如下一段判断处理

  1. if LResponseDigit <> 2 then
  2. begin
  3.   result := wnGoToURL;
  4.   case Response.ResponseCode of
  5.     401:
  6.        ….
  7.     407:
  8.        ….
  9.     else begin
  10.         RaiseException;
  11.     end;
  12.   end;
  13. end;

在返回值不是以2开头的时候,会直接抛掉后面接受到的数据,从而得不到想要的数据。
修改这个函数里面的子函数 RaiseException, 使其由原先的:

  1.   procedure RaiseException;
  2.   var
  3.     LRespStream: TStringStream;
  4.     LTempStream: TStream;
  5.     LTemp: Integer;
  6.   begin
  7.     LTemp := FHTTP.ReadTimeout;
  8.     FHTTP.ReadTimeout := 2000; // Lets wait 2 seconds for any kind of content
  9.     LRespStream := TStringStream.Create('');
  10.     LTempStream := Response.ContentStream;
  11.     Response.ContentStream := LRespStream;
  12.     try
  13.       FHTTP.ReadResult(Response);
  14.       raise EIdHTTPProtocolException.CreateError(Response.ResponseCode, FHTTP.ResponseText, LRespStream.DataString);
  15.     finally
  16.       Response.ContentStream := LTempStream;
  17.       LRespStream.Free;
  18.       FHTTP.ReadTimeout := LTemp;
  19.     end;
  20.   end;

变为

  1.   procedure RaiseException;
  2.   var
  3.     LTemp: Integer;
  4.   begin
  5.     LTemp := FHTTP.ReadTimeout;
  6.     FHTTP.ReadTimeout := 2000; // Lets wait 2 seconds for any kind of content
  7.     try
  8.       FHTTP.ReadResult(Response);
  9.       raise EIdHTTPProtocolException.CreateError(Response.ResponseCode, FHTTP.ResponseText, '');
  10.     finally
  11.       FHTTP.ReadTimeout := LTemp;
  12.     end;
  13.   end;

至此,Response.Stream中存放了返回后的数据,可以继续程序上的处理了。

Popularity: 5% [?]

Random Posts

带附件内容的Soap数据包格式分析

MMS彩信发送在正常的soap xml包体外还需要附加彩信数据,经过抓包分析,发现采用 multipart/related 方式发送。
start部分发送的是Soap的数据包,其他为附加的彩信文件, 采用头部的boundary设定来做多块数据的分隔。
一个抓下来的部分包
post的header头部分

POST /wespa_mms/services/SendMessage HTTP/1.1
Content-Type: multipart/related; boundary=MIMEBoundaryurn_uuid_31E20DB13F6FA8BB9A1234336210043;
  type="text/xml"; start="<0.urn:uuid:31E20DB13F6FA8BB9A1234336210044@apache.org>"
SOAPAction: ""
User-Agent: Axis2
Host: 127.0.0.1:5555
Transfer-Encoding: chunked

post的数据体部分

--MIMEBoundaryurn_uuid_31E20DB13F6FA8BB9A1234336210043
Content-Type: text/xml; charset=UTF-8
Content-Transfer-Encoding: 8bit
Content-ID: <0.urn:uuid:31E20DB13F6FA8BB9A1234336210044@apache.org>

<?xml version='1.0' encoding='UTF-8'?>xml包体内容
--MIMEBoundaryurn_uuid_31E20DB13F6FA8BB9A1234336210043
Content-Type: text/plain
Content-Transfer-Encoding: binary
Content-ID: <att_file2>

file2文件内容
--MIMEBoundaryurn_uuid_31E20DB13F6FA8BB9A1234336210043
Content-Type: text/plain
Content-Transfer-Encoding: binary
Content-ID: <file_1>

file_1文件内容
--MIMEBoundaryurn_uuid_31E20DB13F6FA8BB9A1234336210043--

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

Indy 的 ReadTimeOut 设置失效?

最近在做MMS彩信接口程序,因为不使用Java平台,运营商所提供的Java版的MMS开发包无用,只好按照通信协议用indy直接连接服务端发送拼装好的数据封包来做处理。

为了将自己程序发出的封包和使用java开发包发出的数据包做对比,使用indy做了一个简单的tcpserver来接收发出的封包数据做保存。发现设置的ReadTimeOut设置无效,到了设置的超时时间仍然会处于阻塞状态,只有连接断开才可以继续下去。

网上搜索了一下,发现这个问题是Indy早期版本存在的Bug,indy采用的是阻塞模式,如果Server端未返回信息,这个readln会一直等下去,设置的TimeOut不会起作用(处于死循环中,没有跳出条件),是个BUG。
INDY团队给出的解决办法如下:
第一种:
对ReadFromStack函数的最后一小段做修改:

until   (LByteCount   <>   0)   or   (Connected   =   False);

修改为:

until   (LByteCount   <>   0)   or   (Connected   =   False)   or   (Result  =   -1);

第二种:
在  ReadFromStack()  的后面 // TimeOut 后面位置

//   Timeout
if   ARaiseExceptionOnTimeout   then   begin
raise   EIdReadTimeout.Create(RSReadTimeout);
end;
Result   :=   -1;

修改为:

//   Timeout
Result   :=   -1;   //   MOVED!
if   ARaiseExceptionOnTimeout   then   begin
raise   EIdReadTimeout.Create(RSReadTimeout);
end   else   //   ADDED!
break;   //   ADDED!

按照以上方法中的一个做了修改,再次接受数据内容,不会处于死等问题。

Popularity: 5% [?]

Related

Delphi2009正式版发布了

Delphi2009发布了,在网上找了一些地址下载不过要么是连接数过多,无法下载,要么是要下载一个特别的下载工具再下载,最后总算找到一个有可以下载地址连接的页面。

http://www.soapui.cn/wordpress/index.php/archives/35

里面有文件下载地址,需要每个文件单独下载,麻烦,不过有FlashGet这样的工具,下载整个页面上连接文件也简单。
同时这个页面上还有特别文件的下载地址,就不要再到别处找了。

刚好周末了,回家慢慢下载,等着做Delphi2009的使用体验。

Popularity: 3% [?]

Related

使用Delphi4Php的模板功能

Delphi4php使用了smarty做为其内部的模板引擎,在实际使用中,我们只要设置 Page 的 TemplateEngine 属性值为 SmartyTemplate,并将 TemplateFileName 属性设置为该页面对应的 模板文件,在实际使用的时候就会使用模板中设置的布局来显示。

模板文件遵循Smarty 的风格,区别就是使用 {% 和 %} 来包含模板脚本内容, 而不是我们习惯的 { 和 }包含。

在模板中可以直接使用在 Page 上定义的属性,比如,在 Page 上放一个 Label 取名称 lbTest, 则在模板文件中可以通过 {% $lbTest %} 来将lbTest的Label显示出来, 被显示的lbTest将按照lbTest所定义的各种属性行为来表现,比如字体的大小颜色等,对 lbTest 定义的事件处理方法也会转化为相关的脚本调用。

默认模板可以使用在Page上放置的组件变量,如果要在模板中使用非Page上放置的组件对象,则需要设置Page 的 OnTemplate 事件, 比如。

  1.        function IndexTemplate($sender, $params)
  2.        {
  3.           // 获取使用的模板引擎对象
  4.           $smarty = $params['template']->_smarty;
  5.           // 为模板设置一些非控件的变量值,这儿设置变量名称为 test
  6.           $smarty->assign('test', "测试额外变量文字");
  7.        }

然后在模板中使用 {% $test %} 就可以显示在这儿设置的文字内容。

——-
我测试时发现一个问题,如果在设计时指定好 Page 的 TemplateEngine 和 TemplateFileName,则在修改模板内容并做保存时,会将Page的事件处理关联关系去除,而且按F11不能编辑Page的属性了,不知道是Delphi4Php的Bug问题还是我的RP问题。
好在通过在设计时先不设置这两个属性的值,然后在Page的OnCreate中动态的设置这两个属性的值可以解决这个问题。

  1.        function IndexCreate($sender, $params)
  2.        {
  3.            $this->TemplateEngine = "SmartyTemplate";
  4.            $this->TemplateFilename = "index.tpl";
  5.        }

Popularity: 4% [?]

Related

← Previous PageNext Page →