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

2023-11-27

我有一个 Android 应用程序使用 Indy 10 TIdHttpServer(Delphi 2006 附带)与 Delphi 2006 Web 服务应用程序进行通信。 Delphi 应用程序生成一个大的 XML 文件并为其提供服务。 XML 生成可能持续超过 5 分钟。

如果持续时间为GenerateXml()超过约 5 分钟 (*),我检测到错误 10053TIdHTTPResponseInfo.WriteContent如果在 Delphi IDE 中运行:

Socket Error # 10053 Software caused connection abort.

但是,在 android 端没有检测到任何内容,并且HttpGet- 通话永远持续。

我的问题是:

1.) 为什么我会收到错误 10053 以及如何避免它?看起来android连接超时了,但是http.socket.timeout设置为无限。

and

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;

Edit:(*) 我做了进一步的测试,即使整个过程持续时间不到 2 分钟,也遇到了错误。


Android 和服务器之间的某些东西(例如防火墙/路由器)可能会在闲置太长时间后切断连接。您应该尝试启用 TCP keep-alive 以避免这种情况。

另一方面,这就是 HTTP 1.1 的情况分块传输编码旨在处理(假设您开始使用 HTTP 1.1)。您应该在生成 XML 时将其分段发送,而不是等待 5 分钟完整生成整个 XML,然后再将其发送到客户端。这不仅可以保持连接处于活动状态,还可以减少服务器的内存占用,因为它不必一次性将整个 XML 存储在内存中。

TIdHTTPServer(还)本身不支持发送分块响应(但是TIdHTTP确实支持接收分块响应),但是手动实现并不困难。写一个自定义TStream派生类并覆盖其虚拟Write()方法(或使用 Indy 的TIdEventStream类)使用中概述的格式将数据写入 HTTP 客户端RFC 2616 第 3.6.1 节。有了它,你就可以拥有ServeXmlDoc()设置ResponseInfo.TransferEncoding财产给'chunked'并致电ResponseInfo.WriteHeader()方法无需设置ResponseInfo.ContentText or ResponseInfo.ContentStream属性,然后将您的自定义流传递给IXMLDocument.SaveToStream()因此它将在标头之后完成响应数据的写入。例如:

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 内容时。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

  • CardView 圆角获得意想不到的白色

    When using rounded corner in CardView shows a white border in rounded area which is mostly visible in dark environment F
  • 谷歌坐标认证

    当我尝试连接到 Google 坐标时 总是出现异常GoogleAuthException 我拥有 Google 地图协调中心许可证 我确实使用我的包应用程序名称和 SHA1 在 google 控制台中创建了我的客户端 ID 我将权限添加到清
  • 如何使用 Ruby on Rails 3 检查 HTTP 请求的“Content-Length”字段?

    我正在使用 Ruby on Rails 3 在我的视图文件中我有以下代码 为了避免服务器过载 我会在服务器接收上传文件之前检查上传文件的大小 这是因为 按下表单的提交按钮 服务器会先完整接收文件 然后再检查文件 我知道一个HTTP 请求有标
  • android xamarin 中的 reCaptcha

    我想在 Xamarin android 应用程序中实现验证码 我抓住了这个在 Android 中集成 googles reCaptcha 验证 https www c sharpcorner com article how to integ
  • 当文本输入聚焦在 React Native for Android 的底部工作表上时,视图移出屏幕

    我正在使用图书馆 https github com osdnk react native reanimated bottom sheet https github com osdnk react native reanimated bott
  • Adobe 是否为其 PDF 阅读器提供 Android SDK 或 API? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我希望能够在我们的应用程序内的视图中显示本地 PDF 文件 在 Android 4 03 下的平板电脑上运行 目前 我们将 Adob eR
  • Android SIP 来电使用带有广播接收器的服务

    大家好 其实我正在尝试创建一个应用程序 支持基于 SIP 通过互联网进行音频呼叫 这里使用本机 sip 我遇到了来电问题 我已经完成了服务的注册部分 但是在接听电话时我无法接听电话 请帮助我 Service file package exa
  • JavaMail 只获取新邮件

    我想知道是否有一种方法可以在javamail中只获取新消息 例如 在初始加载时 获取收件箱中的所有消息并存储它们 然后 每当应用程序再次加载时 仅获取新消息 而不是再次重新加载它们 javamail 可以做到这一点吗 它是如何工作的 一些背
  • 获取当前 android.intent.category.LAUNCHER 活动的实例

    我创建了一个库项目 并在多个应用程序之间共享 我实现了一个简单的会话过期功能 该功能将在一段时间后将用户踢回到登录屏幕 登录屏幕活动是我的主要活动 因此在清单中它看起来像这样
  • Ubuntu 16.04 - Genymotion:找不到 /dev/hw_random

    I install Genymotion on the Ubuntu 16 04 64Bit I created a virtual emulator for Android 6 0 then I run this emulator but
  • Google 云端硬盘身份验证异常 - 需要许可吗? (v2)

    我一直在尝试将 Google Drive v2 添加到我的 Android 应用程序中 但无法获得授权 我收到 UserRecoverableAuthIOException 并显示消息 NeedPermission 我感觉 Google A
  • 如何在运行时(Delphi/Windows)程序中添加代码?

    我正在Windows XP Delphi 7上工作 我需要在正在运行的程序中添加一些过程 或函数 并且我不想在完成后再次重新编译它 我只有一个具有 5 个功能的主机应用程序来发送不同类型的警报 但是还有其他新的警报类型 所以我必须执行新的功
  • Android Studio 0.4.3 Eclipse项目没有gradle

    在此版本之前 在 Android Studio 中按原样打开 Eclipse 项目似乎很容易 无需任何转换 我更喜欢 Android Studio 环境 但我正在开发一个使用 eclipse 作为主要 IDE 的项目 我不想只为这个项目下载
  • Mac 上的 Delphi - 可能吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我负责一个 Delphi Win32 项目管理应用程序 我刚刚完成了向 Delphi 2009 的迁移
  • 我的设备突然没有显示在“Android 设备选择器”中

    我正在使用我的三星 Galaxy3 设备来测试过去两个月的应用程序 它运行良好 但从今天早上开始 当我将设备连接到系统时 它突然没有显示在 Android 设备选择器 窗口中 我检查过 USB 调试模式仅在我的设备中处于选中状态 谁能猜出问
  • 如何根据 gradle 风格设置变量

    我想传递一个变量test我为每种风格设置了不同的值作为 NDK 的定义 但出于某种原因 他总是忽略了最后味道的价值 这是 build gradle apply plugin com android library def test andr
  • Android 套接字和 asynctask

    我即将开始制作一个应该充当 tcp 聊天客户端的应用程序 我一直在阅读和阅读 我得出的结论是最好 如果不需要 将我的套接字和异步任务中的阅读器 问题是我不确定从哪里开始 因为我是 Android 新手 这至少对我来说是一项艰巨的任务 但据我
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 将两个文本视图并排放置在布局中

    我有两个文本视图 需要在布局中并排放置 并且必须遵守两条规则 Textview2 始终需要完整显示 如果布局中没有足够的空间 则必须裁剪 Textview1 例子 文本视图1 文本视图2 Teeeeeeeeeeeeeeeeeextview1
  • 如何将 google+ 登录集成到我的 Android 应用程序中?

    大家好 实际上我需要通过我的应用程序从 google 登录人们 现在我阅读了 google 上的文档 其中指出 要允许用户登录 请将 Google Sign In 集成到您的应用中 初始化 GoogleApiClient 对象时 请求 PL

随机推荐