Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Problem with Indy TCPClient or IOHandler
#1
Hi Guys

We are having some bugs in our application after migrating our source code from delphi 7 to XE2. Indy 9 and  was used in delphi 7 and XE2 respectively. 

The application is dll encapsulated windows COM Object and hosted with GUI.  

We use TCPClient that continuously send and receive data from a device (Server) every 2 seconds. Sending of data to the server is done in the Main Thread while reading the response in another Thread. FIdClient.IOHandler.Write(sData + FSendRcvTerminator, TEncoding.ANSI) for sending the data and reading with FClient.IOHandler.ReadBytes(LBuffer, -1, false). The application do work perfectly for days or weeks without any problem but after a while all the processes in the Main Thread hanged and stop responding meanwhile the processes in the other Thread continue working. It has been very difficult for us to locate the course of this problem.  Sending data with FIdClient.IOHandler.Write(sData + FSendRcvTerminator, TEncoding.ANSI)  to the Server from the other Thread gets the hanged processes in Main Thread working again. We are actually not satisfy with this workaround and want to know the course. The same code written in delphi 7 and Indy 9 is working without any problem.

The only difference in our code is that with indy 9 we did not use IOHandler to write or read from the socket.  What are we doing wrong here!       
       
Thanks
Reply
#2
(06-28-2018, 08:32 AM)Ayodeji Wrote: We are having some bugs in our application after migrating our source code from delphi 7 to XE2. Indy 9 and  was used in delphi 7 and XE2 respectively. 

I assume you mean Indy 10 in XE2.

(06-28-2018, 08:32 AM)Ayodeji Wrote: Sending of data to the server is done in the Main Thread

That is generally not a good idea. You really should be using a worker thread for that, to avoid blocking the UI.

(06-28-2018, 08:32 AM)Ayodeji Wrote: while reading the response in another Thread.

That is good.

(06-28-2018, 08:32 AM)Ayodeji Wrote: FIdClient.IOHandler.Write(sData + FSendRcvTerminator, TEncoding.ANSI) for sending the data and reading with FClient.IOHandler.ReadBytes(LBuffer, -1, false).

Calling ReadBytes() in that way returns whatever bytes are currently in the socket *at that moment*. Is that what you really want? That runs the risk of receiving partial data, is your code prepared to handle that possibility? Doesn't the communications have structure to it? You are sending a terminator after your outgoing data, does the inbound data have a similar terminator on each message? If so, then why not use IOHandler.ReadLn() or IOHandler.WaitFor() with that terminator passed in as a parameter?

(06-28-2018, 08:32 AM)Ayodeji Wrote: The application do work perfectly for days or weeks without any problem but after a while all the processes in the Main Thread hanged and stop responding

All the more reason NOT to do non-UI work in the main UI thread. It doesn't belong there.

(06-28-2018, 08:32 AM)Ayodeji Wrote: Sending data with FIdClient.IOHandler.Write(sData + FSendRcvTerminator, TEncoding.ANSI)  to the Server from the other Thread gets the hanged processes in Main Thread working again.

Without seeing your actual code, that kind of behavior implies to me that the UI thread is blocked waiting to receive a reply to something it thinks was sent out but really wasn't, so when the worker thread sends it out, it unblocks whatever the UI thread is waiting for.

(06-28-2018, 08:32 AM)Ayodeji Wrote: What are we doing wrong here!

I can't really answer that since you did not show any of your code.

Reply
#3
(06-28-2018, 05:51 PM)rlebeau Wrote: I assume you mean Indy 10 in XE2. 

Thanks for the quick reply, yes i mean XE2. 

(06-28-2018, 08:32 AM)rlebeau Wrote: That is generally not a good idea.  You really should be using a worker thread for that, to avoid blocking the UI.

The Indy TCPClient component is not directly use in UI and doesn't have direct interaction with UI, The Main Thread that I am referring to is implemented in dll. Then we have a standalone UI application that loads the dll.    

(06-28-2018, 08:32 AM)rlebeau Wrote: Calling ReadBytes() in that way returns whatever bytes are currently in the socket *at that moment*.  Is that what you really want?  That runs the risk of receiving partiual data, is your code prepared to handle that possibility?  Doesn't the communications have structure to it?  You are sending a terminator after your outgoing data, does the inbound data have a similar terminator on each message?  If so, then why not use IOHandler.ReadLn() or IOHandler.WaitFor() with that terminator passed in as a parameter?

The code can handle partial data. Yes it has a communication structure with terminator for outbound and inbound data. We didn't have any problem reading the data.

(06-28-2018, 08:32 AM)rlebeau Wrote: All the more reason NOT to do non-UI work in the main UI thread.  It doesn't belong there.

The implementation of TCPClient that send to server is not in UI Main Thread.

(06-28-2018, 08:32 AM)rlebeau Wrote: Without seeing your actual code, that kind of behavior implies to me that the UI thread is blocked waiting to receive a reply to something it thinks was sent out but really wasn't, so when the worker thread sends it out, it unblocks whatever the UI thread is waiting for.

I might consider writing a worker Thread inside the dll. Are there ways to know when the thread is blocked and probably the best way to unblock it?

(06-28-2018, 08:32 AM)rlebeau Wrote: I can't really answer that since you did not show any of your code.

My Boss wouldn't allow me to post the code here.
Reply
#4
(06-29-2018, 02:41 PM)Ayodeji Wrote: The Indy TCPClient component is not directly use in UI and doesn't have direct interaction with UI, The Main Thread that I am referring to is implemented in dll. Then we have a standalone UI application that loads the dll.    

Just because it is implemented in a DLL does not change how threading works. As you said earlier: "Sending of data to the server is done in the Main Thread". Whether the code is implemented inside a DLL or inside the app itself, it should not be executed in the main UI thread, but rather in a worker thread. The UI thread should ONLY service the UI and NOTHING ELSE.

(06-29-2018, 02:41 PM)Ayodeji Wrote: The code can handle partial data. Yes it has a communication structure with terminator for outbound and inbound data. We didn't have any problem reading the data.

Well, clearly you do have issues with how you are managing the communications, or you would not be asking for help here.

If the communication has structure to it, then why aren't you waiting for a complete message to arrive before you process it? Why are you reading it in arbitrary blocks of partial data? You shouldn't be doing it that way. One of Indy's strengths is being able to handle structured data.

(06-29-2018, 02:41 PM)Ayodeji Wrote: The implementation of TCPClient that send to server is not in UI Main Thread.

That is not what you said earlier (see above).

(06-29-2018, 02:41 PM)Ayodeji Wrote: My Boss wouldn't allow me to post the code here.

Then I can't help you further with your UI blocking issue. Based on everything you have described so far, it is clear that you are not using Indy correctly/effectively, but without seeing CODE, I can't tell you what is wrong with it, or how to make it work correctly/better.

Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)