gpt4 book ai didi

android - 如果 Android 中的 HttpGet 操作持续时间过长,如何避免出现错误 10053 (WSAECONNABORTED)?

转载 作者:太空狗 更新时间:2023-10-29 12:45:42 24 4
gpt4 key购买 nike

我有一个 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.ContentTextResponseInfo.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/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com