0

I'm setting up a new server, and I have a deadlock on waiting to receive data from the server.

On the client-side, I add a new thread to handle net program and on execute segment, first create a TIdTCPClient and connect to the server. Sending login data and when the connection has done sending data and receives ack sign. All is fine, but on connection loss or dead when I waiting to receive ack from the server my code is blocked.

Here is my sample code:

if sending_buf(Buffer_to_send) then//send my data to server                         
  //wait to receive ack from server
try
  In_buffer:= nil;                                
  IdTCPClient1.IOHandler.ReadBytes(In_buffer,-1,false);// here is my problem!!! 
    if In_buffer <> nil then
      begin
        //received ack answer do other prosses...
      end
    else
      begin
        //on timeout
      end;
except on e : Exception do
  begin
    SendHis('Error= ' + e.Message);//send error to main thread
    raise;
  end;

How to determine if the connection is lost or dead on the ReadBytes() line?

And here is my short server code:

   try
exc2_getdata1:
  if AContext.Connection.Connected then
      begin
    byte_buffer:= nil;
                with AContext.Connection.IOHandler do
                begin
                   if CheckForDataOnSource(5000) then
                     begin
                          if not InputBufferIsEmpty then
                            begin
                              InputBuffer.ExtractToBytes(byte_buffer);
                            end
                          else
                            begin
                              goto exc2_getdata1;
                            end;
                     end
                   else
                     begin
                         //timeout
                         goto exc2_getdata1;
                     end;
                end;
      end;
  except
      on e : Exception do
          begin
            //do something
            raise;
          end;

    end;
//check validate and use data, after prosses send ack to client
    SetLength(Buffer_to_send,1 + sizeof(integer));//1 is the ack sign short integer and other is received packet id
                Buffer_to_send[0]:= ack_s;//is short integer ack sign
                move(byte_buffer[2],Buffer_to_send[1],sizeof(integer));//copy the received id to out buffer
                try
                  if not CheckBox1.Checked then //add this line to skip sending ack to client for simulate error
                    AContext.Connection.IOHandler.write(Buffer_to_send); //send ack to client
                except
                    //do something
                    raise;
                end;
  • Assign a reasonable non-infinite timeout for the `IdTCPClient1.ReadTimeout`, and maybe also enable TCP keepalives via `IdTCPClient.Socket.Binding.SetKeepAliveValues()`. – Remy Lebeau Aug 17 '19 at 07:43
  • Thanks, I set ReadTimeout to 10000 and check In_buffer size after ReadBytes to validate received data and timeout. Only when the connection dead on executing "IdTCPClient1.IOHandler.ReadBytes" time my code is locked here and I don't know how to resolve this problem. I change the code in server_side and skipping to send Ack to the client and there is no problem and my code determine the timeout event. When I disconnect the server while the client waiting to receive Ack from the server my code is blocked and no timeout and exception happen. Can you send to me more detail or any source? – R_D Safatco Aug 17 '19 at 10:00
  • please show your server code. What does your protocol actually look like? Why are you using `ReadBytes()` with `AByteCount=-1` at all, rather than something more structured? – Remy Lebeau Aug 17 '19 at 20:16
  • I edit my question and add short server code. I use a simple protocol and flow step by step. Use AByteCount=-1 to read all received byte. I prevent the server to send ack to the client by checking the checkbox and on the client timeout occurs and all action is on the control. when i simulate the connection loss or dead by shutting down the server program while the client is waiting to receive ack from the server, my program in the client_side is locked at readbyte line. – R_D Safatco Aug 17 '19 at 22:47
  • How can I get the control of my code in client-side, when it blocked at readbyte line? – R_D Safatco Aug 17 '19 at 22:51
  • your server is sending an ack byte followed by an integer. The IOHandler has `Write(Byte)`, `Write(Int32)`, `ReadByte()` and `ReadInt32()` methods, you should use them. Stay away from `Write(TIdBytes)` and `ReadBytes()` except when absolutely necessary. Also, accessing `CheckBox1.Checked` is not thread-safe, you MUST sync with the main UI thread when accessing UI controls in `TIdTCPServer` events – Remy Lebeau Aug 18 '19 at 00:11
  • Write(Byte), Write(Int32), ReadByte() and ReadInt32() methods return one variable and i need array of byte to prosses. checkbox1 is temporary and I remove it soon. My current problem is to resolve locked my code on ReadBytes line in client-side. that is block my code on unknow network error and don't return any thing. Can you help me to unblock this event? How I can skip this line and do an action for this condition? – R_D Safatco Aug 18 '19 at 02:20

0 Answers0