微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Rest数据连接期间的Android Socket超时异常,仅在移动网络连接期间

如何解决Rest数据连接期间的Android Socket超时异常,仅在移动网络连接期间

在将 Delphi 10.1 版本更新到 10.4.2 后,我遇到了这个问题,该问题仅出现在部分 Android 10 和 11 设备上。

APP 通过 TDSRestConnection 与服务器交换数据。 在同一部手机上,之前使用 Delphi 10.1 开发的应用可以正常工作,但在更新到 Delphi 10.4.2 版和手机上的 Android 升级后停止工作。

APP只能在WiFi网络上工作,不再在移动网络上工作,一段时间后(7/8秒)产生这个错误

java.net.socketTimeoutException:300000 毫秒后无法从 /100.118.154.102(端口 42050)连接到 /xxx.xxx.xx.xx(端口 17200):isConnected 失败:ETIMEDOUT(连接超时)。

我还尝试使用不同的互联网移动提供商(TIM、VODAFONE) 4G连接很好,网速测试没有问题。

错误不会立即出现。 函数 Getsql 在 sincro 过程中被多次调用,但不幸的是它不是在同一点停止工作。

代码

客户端:

const fConnectTimeout=300000;
const fReadTimeout=300000;


function TServerMethods1Client.Getsql(Stringasql: string; const ARequestFilter: string): TFDJSONDataSets;
begin
  if fgetsqlCommand = nil then
  begin
    fgetsqlCommand := FConnection.CreateCommand;
    fgetsqlCommand.RequestType := 'GET';
    fgetsqlCommand.Text := 'TServerMethods1.Getsql';
    fgetsqlCommand.Prepare(TServerMethods1_Getsql);
  end;
  fgetsqlCommand.Parameters[0].Value.SetWideString(Stringasql);
  fgetsqlCommand.Execute(ARequestFilter);
  if not fgetsqlCommand.Parameters[1].Value.IsNull then
  begin
    FUnMarshal := TDSrestcommand(fgetsqlCommand.Parameters[1].ConnectionHandler).GetJSONUnMarshaler;
    try
      Result := TFDJSONDataSets(FUnMarshal.UnMarshal(fgetsqlCommand.Parameters[1].Value.GetJSONValue(True)));
      if FInstanceOwner then
        fgetsqlCommand.FreeOnExecute(Result);
    finally
      FreeAndNil(FUnMarshal)
    end
  end
  else
    Result := nil;
end;

function Selectsql(Stringasql:String;tb:TFDMemTable;out Errore:String):Boolean; overload;
var
  jds: TFDJSONDataSets;
  data: TFDAdaptedDataSet;
begin
  try

     result:=false;

     if DMClientRestModule=nil then DMClientRestModule:=TDMClientRestModule.Create(nil);

     DMClientRestModule.DSRestConnection1.Port := STRTOINT(REST_PORT);
     DMClientRestModule.DSRestConnection1.Host := REST_HOST;
     DMClientRestModule.DSRestConnection1.SessionID := '';
     DMClientRestModule.DSRestConnection1.HTTP.ConnectTimeout := fConnectTimeout;
     DMClientRestModule.DSRestConnection1.HTTP.ReadTimeout := fReadTimeout;

     jds :=TFDJSONDataSets.Create;

     jds := DMClientRestModule.ServerMethods1Client.Getsql(Stringasql);
     if (Assigned(jds)) then begin
       data := TFDJSONDataSetsReader.GetListValue(jds,0);
       tb.AppendData(data);
       tb.Open;
       result:=true;
     end;


     try
       DMClientRestModule.Free;
       DMClientRestModule:=NIL;
     except
     end;

  except
     result:=false;
     Errore:=GetStrException(ExceptObject,ExceptAddr);
  end;

END;

服务器端:

function TServerMethods1.Getsql(Stringasql: String): TFDJSONDataSets;
var
 dset:TFDJSONDataSets;
begin

try

 DbConn.Params.Clear; //TFDConnection
 DbConn.Params.Database:=fdb;
 DbConn.Params.UserName:=fuid;
 DbConn.Params.Password:=fpwd;
 DbConn.Params.Add('server='+fdbserver);
 DbConn.Params.Add('port='+fport);
 DbConn.Params.DriverID:='MysqL';

try
 q1.Close; // TFDQuery

 if not DbConn.Connected then
  DbConn.Connected:=true;

 if not DbConn.Connected then
     log('Not conneted to db')
      else
       log('Connected to db')  ;
  with q1 do
   begin
    close;
    sql.Clear;
    sql.Add(Stringasql);
    Log(Stringasql);
    open;
   end;

  Result := TFDJSONDataSets.Create;
  // The "TFDJSONDataSetsWriter" class provides static "ListAdd" method.
  // It uses reflection to convert results of the query into "TFDJSONDataSets".
  TFDJSONDataSetsWriter.ListAdd(Result,'',q1);
except
  Log(GetStrException(ExceptObject,ExceptAddr));
  Result := TFDJSONDataSets.Create;
  TFDJSONDataSetsWriter.ListAdd(Result,q1);
end;
finally
  DbConn.Connected:=false;
end;

end;

更新 16/04/2021

查的比较好,好像是导致异常的sql String如下(Long text sql string)

          Stringasql :='SELECT PLANNING_ENGINEERS.DATE_JOB,NOT_A_JOB,';
          Stringasql := Stringasql + ' PLANNING.PLAN_ID,PLANNING.CONTACTID,PLANNING.CALLER_REFER,';
          Stringasql := Stringasql + ' PLANNING.COMPANYID,PLANNING.DEPOTID,CALLTYPEID,TIME_BEGIN,';
          Stringasql := Stringasql + ' TIME_END,LOCATION_DESCRIPTION,ADDRESS1,ADDRESS2,ZIP,PLACE,PROVINCE,';
          Stringasql := Stringasql + ' PHONE1,PHONE2,FAX,EMAIL,LATITUDE,LONGITUDE,';
          Stringasql := Stringasql + ' PLANNING.DELETED,PLANNING.CLOSED,PLANNING.SUSPENDED,PLANNING.NOTES,';
          Stringasql := Stringasql + ' PLANNING.INTERNAL_NOTES,PLANNING.SUGGESTION_NOTES,PLANNING.CLOSING_NOTES,ORDER_REFERENCE,EXTERNAL_REFERENCE,';
          Stringasql := Stringasql + ' EXTERNAL_REFERENCE_DESC ';
          Stringasql := Stringasql + ',(SELECT CALLTYPES.DESCRIPTION FROM CALLTYPES WHERE CALLTYPES.CALLTYPE_ID=PLANNING.CALLTYPEID)';
          Stringasql := Stringasql + ' AS CALL_DESC ';
          Stringasql := Stringasql + ',(SELECT CALLTYPES.TYPE FROM CALLTYPES WHERE CALLTYPES.CALLTYPE_ID=PLANNING.CALLTYPEID)';
          Stringasql := Stringasql + ' AS CALL_TYPE ';
          Stringasql := Stringasql + ',(SELECT DEPOTS.NOTES FROM DEPOTS WHERE DEPOTS.DEPOT_ID=PLANNING.DEPOTID)';
          Stringasql := Stringasql + ' AS DEPOT_NOTES ';
          Stringasql := Stringasql + ' FROM PLANNING,PLANNING_ENGINEERS WHERE  ';
          Stringasql := Stringasql + ' PLANNING.DELETED=''N'' AND PLANNING.CLOSED=''N'' AND PLANNING.SUSPENDED=''N'' ';
          Stringasql := Stringasql + ' AND PLANNING_ENGINEERS.PLANID=PLAN_ID ';
          Stringasql := Stringasql + ' AND PLANNING_ENGINEERS.ENGINEERID='+'42';
          Stringasql := Stringasql + ' AND PLANNING_ENGINEERS.DATE_JOB BETWEEN '+QuotedStr(FormatDateTime('YYYYMMDD',date))+' AND '+QuotedStr(FormatDateTime('YYYYMMDD',date))+' ';
          Stringasql := Stringasql + ' ORDER BY DATE_JOB,TIME_BEGIN';

在WIFI连接期间,对服务器的调用工作正常,然后将结果发回。

而是在 4G 连接期间,调用引发以下异常:

模块中的异常 ENetHTTPClientException ... java.net.socketException : 连接重置。

我还向 Embarcadero 报告了ticket RSP-33699

视频如下:RestIssue

解决方法

我想您使用明文 HTTP(即 http://172.16.30.24:8088)。考虑给定的解决方案:)

从 Delphi 10.1 升级到 10.4.1 更改了您项目中的目标 SDK。您可能期望的更改之一是 Android 不允许您使用从 Android 9 开始的直接明文 HTTP 请求。

在您的 AndroidManifest.xml 文件中,您需要记住互联网权限并添加如下所示的一行:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...>
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        ...
        android:usesCleartextTraffic="true"
        ...>
        ...
    </application>
</manifest>

可在此处找到更多信息:StackOverflowAndroid docs

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。