- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 Android 应用程序使用 Indy 10 TIdHttpServer(Delphi 2006 附带)与 Delphi 2006 Web 服务应用程序通信。 Delphi 应用程序生成一个大的 XML 文件并为其提供服务。 XML 生成可能会持续 5 分钟以上。
如果 GenerateXml()
的持续时间超过大约 5 分钟 (*),如果在 Delphi IDE 中运行,我会在 TIdHTTPResponseInfo.WriteContent
中检测到错误 10053:
Socket Error # 10053 Software caused connection abort.
但是,在 android 端没有检测到任何东西,HttpGet
调用将永远持续。
我的问题是:
1.) 为什么会出现错误 10053,如何避免?看起来 android 超时连接,但 http.socket.timeout
设置为无限。
和
2.) 我能做些什么来在客户端检测到这样的错误(除了设置超时,它必须太大而没有用)?我可以在 TIdHttpServer.OnException 中做些什么吗?
这是我的代码。Android - 下载功能,在 AsyncTask 中运行:
protected static HttpEntity downloadEntity(String url) throws IOException {
HttpClient client = new DefaultHttpClient();
//Check because of Error 10053: but timeout is null -> infinite
Log.d("TAG", "http.socket.timeout: " + client.getParams().getParameter("http.socket.timeout"));
HttpGet get = new HttpGet(url);
HttpResponse response;
try {
//in case of Error 10053 the following call seems to last forever (in PlainSocketImpl.read)
response = client.execute(get);
} catch (ClientProtocolException e) {
//...
}
//...
return response.getEntity();
}
TIdHttpServer.OnCommandGet 的 Delphi 实现:
procedure ServeXmlDoc(XmlDoc: IXMLDocument; ResponseInfo: TIdHTTPResponseInfo);
var
TempStream: TMemoryStream;
begin
ResponseInfo.ContentType := 'text/xml';
TempStream := TMemoryStream.Create;
XMLDoc.SaveToStream(TempStream);
ResponseInfo.FreeContentStream := True;
ResponseInfo.ContentStream := TempStream;
end;
procedure TMyService.HTTPServerCommandGet(AContext: TIdContext; RequestInfo: TIdHTTPRequestInfo;
ResponseInfo: TIdHTTPResponseInfo);
begin
Coinitialize(nil);
try
//...
ServeXmlDoc(GenerateXml(), ResponseInfo);
finally
CoUninitialize;
end;
end;
编辑: (*) 我做了进一步的测试,即使在整个过程持续时间不到 2 分钟的情况下,我也遇到了错误。
最佳答案
Android 和您的服务器之间的某些东西(例如防火墙/路由器)可能会在闲置时间过长后切断连接。您应该尝试启用 TCP keep-alives 来避免这种情况。
另一方面,这种情况是 HTTP 1.1 的 chunked transfer encoding旨在处理(假设您开始使用 HTTP 1.1)。不要等待 5 分钟让整个 XML 完整生成然后再将其发送给客户端,您应该在生成 XML 时分段发送它们。这不仅使连接保持 Activity 状态,而且还减少了服务器的内存占用,因为它不必一次将整个 XML 存储在内存中。
TIdHTTPServer
(目前)还不支持发送分块响应(但 TIdHTTP
确实支持接收分块响应),但是手动实现并不难。编写自定义 TStream
派生类并覆盖其虚拟 Write()
方法(或使用 Indy 的 TIdEventStream
类)以将数据写入 HTTP 客户端,使用RFC 2616 Section 3.6.1 中概述的格式.有了它,您可以让 ServeXmlDoc()
将 ResponseInfo.TransferEncoding
属性设置为 'chunked'
并调用 ResponseInfo.WriteHeader( )
方法而不设置 ResponseInfo.ContentText
或 ResponseInfo.ContentStream
属性,然后将自定义流传递给 IXMLDocument.SaveToStream()
因此它将在 header 之后完成写入响应数据。例如:
type
TMyChunkedStream = class(TStream)
private
fIO: TIdIOHandler;
public
constructor Create(AIO: TIdIOHandler);
function Write(const Buffer; Count: Longint): Longint; override;
procedure Finished;
...
end;
constructor TMyChunkedStream.Create(AIO: TIdIOHandler);
begin
inherited Create;
fIO := AIO;
end;
function TMyChunkedStream.Write(const Buffer; Count: Longint): Longint; override;
begin
if Count > 0 then
begin
fIO.WriteLn(IntToHex(Count, 1));
fIO.Write(RawToBytes(Buffer, Count));
fIO.WriteLn;
end;
Result := Count;
end;
procedure TMyChunkedStream.Finished;
begin
fIO.WriteLn('0');
fIO.WriteLn;
end;
procedure ServeXmlDoc(XmlDoc: IXMLDocument; ResponseInfo: TIdHTTPResponseInfo);
var
TempStream: TMyChunkedStream;
begin
ResponseInfo.ContentType := 'text/xml';
ResponseInfo.TransferEncoding := 'chunked';
ResponseInfo.WriteHeader;
TempStream := TMyChunkedStream.Create(ResponseInfo.Connection.IOHandler);
try
XMLDoc.SaveToStream(TempStream);
TempStream.Finished;
finally
TempStream.Free;
end;
end;
另一方面,如果您等待的大部分时间是在 GenerateXml()
中而不是在 XmlDoc.SaveToStream()
中,那么您需要重新考虑您的服务器设计,并想出一种加速 GenerateXml()
的方法,或者只是摆脱 IXMLDocument
并手动创建 XML,以便您可以使用 发送它ResponseInfo.Connection.IOHandler
在您创建 XML 内容时。
关于android - 如果 Android 中的 HttpGet 操作持续时间过长,如何避免出现错误 10053 (WSAECONNABORTED)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18601630/
我正在努力做到这一点 在我的操作中从数据库获取对象列表(确定) 在 JSP 上打印(确定) 此列表作为 JSP 中的可编辑表出现。我想修改然后将其提交回同一操作以将其保存在我的数据库中(失败。当我使用
我有以下形式的 Linq to Entities 查询: var x = from a in SomeData where ... some conditions ... select
我有以下查询。 var query = Repository.Query() .Where(p => !p.IsDeleted && p.Article.ArticleSections.Cou
我正在编写一个应用程序包,其中包含一个主类,其中主方法与GUI类分开,GUI类包含一个带有jtabbedpane的jframe,它有两个选项卡,第一个选项卡包含一个jtable,称为jtable1,第
以下代码产生错误 The nested query is not supported. Operation1='Case' Operation2='Collect' 问题是我做错了什么?我该如何解决?
我已经为 HA redis 集群(2 个副本、1 个主节点、3 个哨兵)设置了本地 docker 环境。只有哨兵暴露端口(10021、10022、10023)。 我使用的是 stackexchange
我正在 Desk.com 中构建一个“集成 URL”,它使用 Shopify Liquid 模板过滤器语法。对于开始日期为 7 天前而结束日期为现在的查询,此 URL 需要包含“开始日期”和“结束日期
你一定想过。然而情况却不理想,python中只能使用类似于 i++/i--等操作。 python中的自增操作 下面代码几乎是所有程序员在python中进行自增(减)操作的常用
我需要在每个使用 github 操作的手动构建中显示分支。例如:https://gyazo.com/2131bf83b0df1e2157480e5be842d4fb 我应该显示分支而不是一个。 最佳答
我有一个关于 Perl qr 运算符的问题: #!/usr/bin/perl -w &mysplit("a:b:c", /:/); sub mysplit { my($str, $patt
我已经使用 ArgoUML 创建了一个 ERD(实体关系图),我希望在一个类中创建两个操作,它们都具有 void 返回类型。但是,我只能创建一个返回 void 类型的操作。 例如: 我能够将 book
Github 操作仍处于测试阶段并且很新,但我希望有人可以提供帮助。我认为可以在主分支和拉取请求上运行 github 操作,如下所示: on: pull_request push: b
我正在尝试创建一个 Twilio 工作流来调用电话并记录用户所说的内容。为此,我正在使用 Record,但我不确定要在 action 参数中放置什么。 尽管我知道 Twilio 会发送有关调用该 UR
我不确定这是否可行,但值得一试。我正在使用模板缓冲区来减少使用此算法的延迟渲染器中光体积的过度绘制(当相机位于体积之外时): 使用廉价的着色器,将深度测试设置为 LEQUAL 绘制背面,将它们标记在模
有没有聪明的方法来复制 和 重命名 文件通过 GitHub 操作? 我想将一些自述文件复制到 /docs文件夹(:= 同一个 repo,不是远程的!),它们将根据它们的 frontmatter 重命名
我有一个 .csv 文件,其中第一列包含用户名。它们采用 FirstName LastName 的形式。我想获取 FirstName 并将 LastName 的第一个字符添加到它上面,然后删除空格。然
Sitecore 根据 Sitecore 树中定义的项目名称生成 URL, http://samplewebsite/Pages/Sample Page 但我们的客户有兴趣降低所有 URL(页面/示例
我正在尝试进行一些计算,但是一旦我输入金额,它就会完成。我只是希望通过单击按钮而不是自动发生这种情况。 到目前为止我做了什么: Angular JS - programming-fr
我的公司创建了一种在环境之间移动文件的复杂方法,现在我们希望将某些构建的 JS 文件(已转换和缩小)从一个 github 存储库移动到另一个。使用 github 操作可以实现这一点吗? 最佳答案 最简
在我的代码中,我创建了一个 JSONArray 对象。并向 JSONArray 对象添加了两个 JSONObject。我使用的是 json-simple-1.1.jar。我的代码是 package j
我是一名优秀的程序员,十分优秀!