问题描述
在将 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>
可在此处找到更多信息:StackOverflow 和 Android docs