jpfollenius
jpfollenius

Reputation: 16620

Robust unidirectional messages with Indy

I have a client application that should send notify messages to an optional server application. The client should not be influenced by whether the server appliction exists or not. It should try to connect to the server application and send the notify message and in case of errors it should just silently ignore all errors and continue work.

I'm using Indy for the TCP communication but all attempts to avoid error messages showing up (i.e. when ther server application closes while connected to the client) failed.

Is there a way to really make this robust?

Current code looks like this:

if (not Client.Connected) then
  begin
  Client.Host := ServerName;
  Client.Port := ServerPort;
  Client.ConnectTimeout := ConnectTimeout;
  try
    Client.Connect;
  except
    Exit;
  end;
  end
try
  Client.IOHandler.WriteLn ('NOTIFYCHANGE "' + Param + '"');
  Client.IOHandler.WriteBufferFlush;
except
  try
    Client.Disconnect;
  except
    { ignore errors while disconnecting }
  end;
  try
    Client.Connect;
  except
    { ignore errors while connecting }
  end;
end;

Upvotes: 3

Views: 870

Answers (5)

Frank Shearar
Frank Shearar

Reputation: 17132

You don't say whether you're using Indy 9 or 10. I use 9, myself, so the below assumes this.

Why not just this?:

procedure Send(Target: String; Port: Integer; S: String);
var
  C: TIdTcpClient;
begin
  C := TIdTcpClient.Create(nil);
  try
    try
      C.Host := Target;
      C.Port := Port;
      C.Connect;
      try
        C.Write(S);
      finally
        C.Disconnect;
      end;
    except
      // Ignore Indy exceptions
      on EIdException do;
    end;
  finally
    C.Free;
  end;
end;

It's easy enough to turn this into a procedure that uses a pre-existing TIdTcpClient.

Upvotes: 0

Harriv
Harriv

Reputation: 6137

For simple TCP communications task I've used Synapse package, it's not as bloated as Indy and feels "cleaner" to use.

From my recent code:

procedure SendMessage(m: string);
var
  sock : TTCPBlockSocket;
  response : string;
begin
  Sock := TTCPBlockSocket.Create;
  try
    Sock.SetTimeout(200);
    Sock.Connect(PrinterServerAddr, IntToStr(PrinterServerPort));

    Sock.SendString(m);
    response := Sock.RecvString(1000);
  finally
    Sock.Free;
  end;
end;

..
try
  SendMessage(NewMessage);
except
 //..handle exception..
end;

Wrap that inside TThread if you want to avoid blocking your current thread.

Upvotes: 2

Francis Lee
Francis Lee

Reputation: 975

Harriv response is OK, you are describing the behaviour of an UDP connection. I'm using in a similar situation.

Upvotes: 0

Harriv
Harriv

Reputation: 6137

If possible, consider using UDP. It's "connectionless", so sender will just send the message and receiving application will receive it if it is listening to the port. However the sender doesn't get any confirmation about the delivery unless the server sends some kind of acknowledgement.

Upvotes: 0

Rob Kennedy
Rob Kennedy

Reputation: 163317

Do you really get error messages from your program? It's common that when debugging that the debugger detects exceptions and interrupts your program, and some people confuse the debugger's message for a message from their own program. Are you sure that's not the case here? I've written about this situation before. Here's the summary of ways to avoid it:

  • Use "advanced breakpoints" to disable the debugger's exception-interception behavior for a region of code.
  • Configure the debugger to ignore certain classes of exceptions. (This is especially common to do with Indy since it tends to throw many exceptions.)
  • Set the debugger to never interrupt the program on exceptions.
  • Disable integrated debugging altogether.

If the message really is coming from your program and not the debugger, then go back and use the debugger to figure out where the message is coming from. When the message appears, pause the program and look at the call-stack window to find the area of your code that's displaying the message, since it clearly isn't in the code you've shown. The code you've shown is thoroughly suppressing (not handling) all exceptions, even the ones that aren't related to Indy, such as EAccessViolation and EOutOfMemory.

Upvotes: 3

Related Questions