DELPHI盒子
!实时搜索: 盒子论坛 | 注册用户 | 修改信息 | 退出
检举帖 | 全文检索 | 关闭广告 | 捐赠
技术论坛
 用户名
 密  码
自动登陆(30天有效)
忘了密码
≡技术区≡
DELPHI技术
lazarus/fpc/Free Pascal
移动应用开发
Web应用开发
数据库专区
报表专区
网络通讯
开源项目
论坛精华贴
≡发布区≡
发布代码
发布控件
文档资料
经典工具
≡事务区≡
网站意见
盒子之家
招聘应聘
信息交换
论坛信息
最新加入: pesamo
今日帖子: 15
在线用户: 10
导航: 论坛 -> 移动应用开发 斑竹:flyers,iamdream  
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/14 17:12:27
标题:
远程调用服务器端的函数提示通讯错误 浏览:1265
加入我的收藏
楼主: delphi 11   安卓调用服务器的函数用于打印报表
提示:Communication timeout error

代码如下:
  MessageDlg('打印前将自动存为草稿,是否继续?', System.UITypes.TMsgDlgType.mtInformation,[TMsgDlgBtn.mbYes,TMsgDlgBtn.mbCancel], 0,
  procedure(const AResult: TModalResult)
   begin
     if AResult = mrYES then
     begin
       if Assigned(Mythreadtask) then
       begin
          if Mythreadtask.Status = TTaskStatus.Running then
          begin
          //If it is already running don't start it again
          Exit;
          end;
       end;
       Mythreadtask := TTask.Create(procedure()
       begin
          try
          ClientModule1.Fc_Server_SM_FmClient.RemoPrint(billvchcode);
          except
          On E:Exception do
          showmessage(e.Message);
          end;
       end);

       Mythreadtask.ExecuteWork;
   end;
打开App第一次调用的时候,服务器端的打印机是打印的,提示Communication timeout error ,但是可以打印,
不退出App,再次调用的时候,连线程都不进入执行。请问这是什么情况呢?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/14 17:14:45
1楼:
使用下面的匿名线程也一样,
TThread.CreateAnonymousThread(procedure()
  var I:integer
  begin
       ..........

        TThread.Synchronize(TThread.CurrentThread,procedure()
        begin
          showmessage(' ..........');
        end);
       ..........

  end).start;

是线程出了问题,还是程序的连接超时的值设置有问题呢?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/6/15 0:40:17
2楼: what is "ClientModule1.Fc_Server_SM_FmClient.RemoPrint(billvchcode);" response?


ex.:
 ClientModule1.Fc_Server_SM_FmClient.RemoPrint(billvchcode);... = true/false/200/400/500 etc... 

exists any response from server when the print is OK? or not?


for example:  if  "RemoPrint(xxxxx)" = false/400 then ... "error"...  wait a time and send again new try...


thread EXECUTE:
...
while Not Terminated do
begin
  try
     LResult:= RemoPrint(xxxxxxx);
     //
     if LResult then
        exit; // OK it was send to print...
  except
     // what to do if any exception?  continue or exit?
     // reset printer....?  send again?   exit?  wait a time?
  end;
  //
  sleep( 5000 ); // wait a time for example to new try?
end;



----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/6/15 3:01:19
3楼: 你的代码:

Mythreadtask := TTask.Create(procedure()
       begin
          try
          ClientModule1.Fc_Server_SM_FmClient.RemoPrint(billvchcode);
          except
          On E:Exception do
          showmessage(e.Message);
          end;
       end);

       Mythreadtask.ExecuteWork;

上述代码,因为是在 Task 里面执行,实际上就是在一个线程里面执行。

在线程里面执行的代码,必须用 try..except..end 包裹起来,否则如果出现异常,整个线程就崩溃了,并且会给程序带来一些意想不到的错误。

你的 except 里面,有一个 ShowMessage,也就是让线程去执行了一个涉及到界面的方法,也会带来意想不到的问题。在线程里面,如果要对界面进行操作,操作界面的代码,需要放到同步里面去。

所以,最简单的测试方法:把 except 后面的代码注释掉,让这个 try..except..end 把异常吃掉,看看类似错误是否还会出现。

如果错误不会出现,说明问题就是 except 后面的代码导致。那你就把 ShowMessage 放到同步里面去,然后再看有没有问题。
----------------------------------------------
-
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/15 17:25:25
4楼:        try
         Button3Click(sender);
         billvchcode:=printVchcode;

         TThread.CreateAnonymousThread(procedure()
         begin
          if  ClientModule1.Fc_Server_SM_FmClient.RemoPrint(billvchcode) =1 then
          begin
          exit;
          end;
         end).start;


         SHOWMESSAGE('单据打印完成!'+billvchcode);
       except
         On E:Exception do
          showmessage(e.Message);
       end;

第一次执行的时候,可以打印,但会提示:
Communication timeout error
第二次执行的时候,不打印,会提示:
External exception 40

还会提示:
Read  timed  OUT 

@pcplayer
@emailx45
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/15 20:34:04
5楼: 如果:
  try
 
    if  ClientModule1.Fc_Server_SM_FmClient.RemoPrint('13') =1 then
          begin
          SHOWMESSAGE('单据打印完成!'+billvchcode);
          exit;
          end;
        except
         On E:Exception do
          showmessage(e.Message);
       end;

不放到线程里执行,打印任务可以完成,但是会提示:Read  timed out 
然后App就闪退了。
这里的Read Time 是指的哪里的Time out 呢?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/15 20:37:16
6楼: 经过多次测试,每次的打印任务都能正确完成,打印机也正常打印,按理说任务已经执行完毕结束了,为啥会报错甚至闪退?真是百思不得其解!如果程序不闪退,再次执行该任务的时候,程序不进入线程里去执行打印任务。好费解。
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/6/16 2:09:17
7楼: 6 楼,我发现我在前面写了那么多,白写了。你根本没仔细看。

你的问题很简单:

1. 如果打印不放到线程里面,会闪退,原因是打印代码执行阻塞时间太长,如果不放线程里面,就是主线程长时间被阻塞没反应,WINDOWS 底下没问题,大不了就是界面冻结一会不响应用户鼠标键盘,而安卓底下,安卓系统会把这样的 APP 杀掉。这就是闪退。

2. 如果打印放到线程底下,我前面已经说了,线程里面的操作,需要把异常用 try..except..end 来把异常吃掉。如果抛出异常,则程序照样会出问题甚至闪退;

3. 如果你非要在线程里面 ShowMessage 这样的操作,那这种操作必须放到同步里面去。
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/6/16 3:23:51
8楼: look my sample using a MyThread

1) im using a PDF Printer for tests ( i dont have any printer in my MSWin)

2) im using "Printer" object (TPrinter class) to send a text to printer

3) im using "StrToInt("hello") to cause an ERROR = Exception for tests

4) im using "InputQuery" to ask to user "yes" or "no" for re-try printing

5) im using "Execute" procedure in my MyThread to controls the print task or inputquery ask to user an answer

6) im using "Printer.Abort" to cancel the printing if user desire...

7) all exception is controlled in my "Try...Except...End" block, then the "MyThread" not end until the user say: NO or press "ESC" or press "CANCEL" button on "InputQuery" or press "Abort" button on the form!!!!

in my video you can that "Printer Queue" receive the files to printing ....

IMPORTANT NOTE:
While the "InputQuery is on the screen" YOU CANNOT KILL/RELEASE THE THREAD!

Then try use a "MODAL" dialog to avoid access the button "Abort or Free" the thread!!!!


see
此帖子包含附件:
GIF 图像
大小:531.7K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/16 10:10:54
9楼: @pcplayer您没白写,我看了,现在我要处理的问题是,找到异常的原因。因为第一次打印正常,第二次打印时似乎并没有进入线程去执行。原因是第一次执行时有异常抛出,我想捕捉异常,但是恼火的是外部错误,不好找到原因。所以我用试错的方法进行排查,谢谢你。
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/16 10:13:38
10楼: @emailx45,当使用PDF打印到文件的时候,需要手动保存一下文件,不然函数返回值几乎在等待。谢谢emailx45
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/6/16 11:22:32
11楼: 你确定你用 try .. except.. end 把异常吃掉了?如果你第一次有异常没处理,线程就已经崩溃了,当然第二次进入不了线程。
----------------------------------------------
-
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/16 14:23:39
12楼: @pcplayer,请看:

  try
//此处需要注释掉,每次调用远程打印没有问题
     sql:='  select BaseNo from B_Person where BaseNo=1 ';
     ClientModule1.ClientDataSet1.Close;
     ClientModule1.ClientDataSet1.CommandText:=sql;
     ClientModule1.ClientDataSet1.Open;
//注释到这里,中间这段
     TThread.CreateAnonymousThread(procedure()
     begin
       try
         if  ClientModule1.Fc_Server_SM_FmClient.RemoPrint('13')=1 then
          begin
          TThread.Synchronize(TThread.CurrentThread,procedure()
          begin
          SHOWMESSAGE('单据打印完成!  '+billvchcode);
          end);
          end;

          except
          On E:Exception do
          TThread.Synchronize(TThread.CurrentThread,procedure()
          begin
          showmessage('1:'+e.Message);// SHOWMESSAGE('单据打印任务失败 !  '+billvchcode);
          end);

          end;
         end).start;

       except
         On E:Exception do
          showmessage('2:'+e.Message);
       end;


第一次执行远程打印,并可以成功打印,
如果在第一次正确打印后,随意执行其他Sql查询后,
再调用远程打印时,就会提示:操作失败,链接已经关闭。错误是1:里面的try捕捉到的
如果,每次调用打印任务后不执行任何SQl查询,则一直可以打印
会不会有一种可能,就是客户端调用服务器端的函数执行后就会关闭连接?可是报错之后,其他功能执行SQl查询依旧可以正确执行。ClientModule1.SQLConnection1的链接是没有问题的。难道还有其他通道?
客户端调用服务器端的难道不是走的ClientModule1.SQLConnection1?
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/6/16 17:02:29
13楼: 1. 我记得你之前说第一次打印,打印成功但会弹异常,然后才是第二次打印不成功;那么,你现在的情况是什么?是第一次打印成功,也没有任何异常,然后第二次打印不成功?

2. ClientModule1.Fc_Server_SM_FmClient.RemoPrint 这句是由线程执行的。这行代码内部究竟是如何工作的,我不知道。但它是否线程安全?比如,如果是在 Windows 底下,你调用的这个方法,它可能用到 WINDOWS 的 COM 控件(比如 ADO 数据库访问),那么,线程调用这样的代码,就需要先执行一次 COM 同步操作的语句。你这里是安卓,有没有其它需要注意的,你要自己查。
----------------------------------------------
-
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/16 18:52:40
14楼: @pcplayer 现在的情况是:
   第一次打印是可以的,正常也不报错了。之前说的第一次打印时会有一个异常,是因为线程调用服务器端的方法时返回值超时导致的,这个已经排除。
目前的情况是:
  在打印界面窗口创建后会执行一些初始化代码,都用到SQL查询。 第一次点击打印,App端工作正常、服务器端工作正常。打印任务结束后,又需要重新执行一些SQL查询,此时线程里执行的:
ClientModule1.Fc_Server_SM_FmClient.RemoPrint  会有一个:操作失败,连接已关闭的错误。
我尝试,在第一次打印后,不进行任何SQL查询,再次发出打印命令时,都能正确执行打印任务。
一旦,执行任何查询语句后,就会:操作失败,连接已关闭的错误。

ClientModule1.Fc_Server_SM_FmClient.RemoPrint  中即使只有:showmewwage('');也会报错。
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/6/17 2:20:55
15楼: @sxfgf 
----------
@emailx45,当使用PDF打印到文件的时候,需要手动保存一下文件,不然函数返回值几乎在等待。谢谢emailx45
----------


sxfgf,您实际上不必等待输入 PDF 文件名!
您可以在调用“PRINTER”对象的打印过程之前告知文件名
Printer.SetPrinter(....) = 设备、驱动程序、端口、模式
----> 端口 = 'myPDFtest.pdf'

这样就不会再问PDF文件名了!!!

请参阅我的示例项目(可执行)
“prjVCL_Thread_TPrinter_InputQuery_Exception_when_printing.exe”

SHA1   = b0168e7a376c7b47d54ab2ce73c6d344bf7db8b2
SHA256 = c869a4460462a7d3321ab5921b867d99ad46ab93777773bb493452cf1f140122


现在,我只测试打印机:“Microsoft Print to PDF”
PDF 文件名将在可执行文件夹中为“myPDFtest.pdf”。
此帖子包含附件:emailx45_202361722021.zip 大小:3.18M
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/6/17 2:36:25
16楼:
我每 2 个“DoPrinting”抛出一个异常

LCounter := LCounter + 1;
如果 (LCounter mod 3) = 0 那么
    StrToInT('你好'); ==> 我的异常 = "InputQuery(....)"


screenshot
此帖子包含附件:
GIF 图像
大小:283.5K
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/18 16:25:26
17楼: @emailx45谢谢
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 sxfgf (FC_FGF) ★☆☆☆☆ -
普通会员
2023/6/18 16:26:15
18楼: @pcplayer谢谢
----------------------------------------------
偶尔做做代码应付一下工作,却发现Delphi已成必配
作者:
男 pcplayer (pcplayer) ★☆☆☆☆ -
普通会员
2023/6/19 1:55:25
19楼: 现在你的问题变成了:

1. 如果只打印,没问题;
2. 如果打印以后,执行 SQL,然后再次打印,会出问题。

那么,你的这个打印代码,和 SQL 之间有什么关系?

正常来说,应该是没有关系的。你这里需要读代码,把关系找出来。

还有,你的 SQL 的执行,是否放在线程中?还是主线程去执行?
----------------------------------------------
-
作者:
男 emailx45 (emailx45) ▲▲▲▲△ -
普通会员
2023/6/19 6:22:17
20楼:
这里有一些尝试的建议:

1)如果从表中读取的数据(记录)量很少或适中,那么您可以在表中进行“循环”并将这些值存储在“数组”/“列表”等中......甚至是普通的字符串! 这样,您就可以避免在线程执行期间访问数据库!

例如:

1)读表记录;
变量
   // 或者任何其他方式,如果有很多字段....
    LMyData:TArray<字符串>; // TDictionary / TList / TStringList / 等等...
开始
    tablex.Open( 'select xxxx from tbHello where xField = yyyyy') ; // ETC...
     而不是 tablex.EOF 做
     开始
       // 存储每条记录的数据...
       LMyData := LMyData + [ MyFieldValue.AsString ];
       tablex.NEXT;
    结尾;
    //
    tablex.CLOSE;


2)创建线程并发送之前读取的数据

MyThread.Create( LMyData .... );
.... 使用“LMyData”处理线程
......打印来自“LMyData”的数据......

MyThread 再见
----------
Here's some advice to try:

1) if the amount of data (records) read from the table is little or moderate, then you could do the "looping" in the table and store these values in an "array"/"list", etc... or even in an ordinary string! This way, you avoid having to access the database during the execution of the thread!

for example:

1) reading table records;
var
   // or any other way if there are many fields....
    LMyData:TArray<string>; // TDictionary / TList / TStringList / etc...
begin
    tablex.Open( 'select xxxx from tbHello where xField = yyyyy') ; // etc...
     while NOT tablex.EOF do
     begin
       // storing data for each record...
       LMyData := LMyData + [ MyFieldValue.AsString ];
       tablex.NEXT;
    end;
    //
    tablex.CLOSE;


2) creating the thread and sending the previously read data

MyThread.Create( LMyData .... );
.... process thread with "LMyData"
..... printing data from "LMyData".......

MyThread BYE BYE
----------------------------------------------
The higher the degree, the greater the respect given to the humblest!RAD 11.3
信息
登陆以后才能回复
Copyright © 2CCC.Com 盒子论坛 v3.0.1 版权所有 页面执行109.375毫秒 RSS