Jump to content
msd

Delphi / TCP/IP Server

Recommended Posts

Hello friends,

 

I need some advice about Delphi as a TCP/IP server from you, Delphi developers.🙂

Scenario: I have about 25 computers with permanent connections to the TCP/IP server component.

Every client has a dedicated server IP address, which is only one point in this story.

Every client sent some HEX code, which I read with ReadByte on the TCP Indy Server, and according to that data, I know the clients locations and IDs.

Those clients are LED displays that represent numeric data sent by a TCP/IP server.

 

Problem: With Indy 10 and Delpi Latest, my app freezes after 1 to 3 hours of use. Only Indy can read those bytes from cache data, and the connection must be permanent.

 

Q: Is there any VCL on the market that has TCP/IP Server-Client with these features?

 

P.S. I tried with demo versions of DevArt Secure Bridge and Internet Component Suite, and I couldn't read bytes, only raw text.

 

Thanks for any advice or help in advance.

Share this post


Link to post

I'm reasonably sure that you can accomplish this with Indy. 

You have multiple clients sending data to a single indy server i assume?

Maybe you have some memory problems, not correct handling incoming connections and or data?

 

 

  • Like 1

Share this post


Link to post

Hello,

 

I assume that when you say "my app freezes" you are referring to the server. Usually when the server freezes is because there is a thread-lock, Indy servers are multi-threaded but the the event handlers are not thread-safe, so if you need to update a VCL control when you read some data, this operation must be done in the main thread (using Synchronize or Queue). 25 concurrent connections is quite low, so Indy server can handle these connections without problems. If you can provide more info about your code we can try to help you.

 

Kind Regards,

Sergio

  • Like 1

Share this post


Link to post

Hello.

 

I have one TCP/IP server by the Indy component and one memo field for some kind of monitoring.

Indy component accepts connection, sends identification request to client, and opens and keeps openend connection.

I'm using three events: OnConnect, OnDisconnect, and, of course, OnExecute.

The first two just accept and log connection status and details; everything else is on the OnExecute event.

I can represent the function that updates the monitoring memo component.

 

function TFServer.cliInfoMessage(info: TMemo; send, msg: string): Boolean;
begin
  TThread.Queue(nil,
    procedure
    begin
      info.Lines.Append('/' + send + '/' + msg);
    end);
result := true;
end;

 

Another function is the response function, which can be bad coded because it does not generate a response for client activity on an open connection.

 

P.S. Yes my app is freeze from r time to time and power up CPU to 100% for few minutes.

 

Thanks again for all...

 

Edited by msd

Share this post


Link to post

besides the threadsafety and the question if this is the best solution, 

probably your memo is getting "full", try to limit the total lines in the memo to for example max. 1000lines, and do the update between beginupdtae and  endupdate.

 

With which intensivity the clients send data )(e,.g. 100 times per second)?

 

 

function TFServer.cliInfoMessage(info: TMemo; send, msg: string): Boolean;
begin
  TThread.Queue(nil,
    procedure
    begin
      info.lines.BeginUpdate(); 
      try
        info.Lines.Append('/' + send + '/' + msg);
        while info.lines.count>1000 do
          info.lines.delete(0);       
      finally
        info.lines.EndUpdate(); 
      end;
    end);
result := true;
end;

Edited by mvanrijnen
  • Thanks 1

Share this post


Link to post

Hello,

 

In peak time, it can be 5–10 times per second (it is not as heavy as it looks in my description).

I have one more method, which is to create a response, and it must be thread-safe. I'll post it here as part of this message.

The whole system has two parts: the first is communication with counters, and the other is information about which counter needs to show which number.

So, all counters are 100% online with an open connection, and after the system receives new data from another side of the system, it must search all connected counters and pass new data.

This is another important part of the code.

 

function TFServer.cliSendData(cliIP: string; cliCMD: string = ''; cliAddress: string = ''; cliValue: string = ''): Boolean;
var
  i: integer;
  cliList: TList;
  byteMsg: TidBytes;
  cntClient: TIdContext;

 

  function SetCounter(dspAddress, dspValue: string): TidBytes;
  begin
    SetLength(bytes, 8);
    bytes[0] := BYTE_START;
    bytes[1] := BYTE_DATA;
    bytes[2] := $31;
    bytes[3] := $00;
    case StrToInt(Copy(cntValue, 1, 2)) of
      00:
        bytes[4] := $00;
      01:
        bytes[4] := $01;
      02:
        bytes[4] := $02;
      03:
    end;
    bytes[5] := $00;
    case StrToInt(cntValue[3]) of
      0:
        bytes[6] := $00;
      1:
        bytes[6] := $01;
      2:
        bytes[6] := $02;
    end;
    bytes[7] := BYTE_STOP;
    result := bytes;
  end;

begin
    byteMsg := SetCounter(cliAddress, cliValue);
    try
      cliList := DisplayServer.Contexts.LockList;
      for i := 0 to cliList.Count - 1 do
      begin
        cntClient := TIdContext(cliList); // AContext.Connection.Disconnect
        if cntClient <> nil then
          try
            if (cliIP = 'ALL') or (cliIP = cntClient.Binding.PeerIP) then
            begin
               cntClient.Connection.IOHandler.Write(byteMsg);
              cliInfoMessage(dspLog, 'SERVER', cliLogDateTime() + ' - Send: ' + cliCMD + ' to Client: - ' + cntClient.Binding.PeerIP);
            end;
          except
          end;
      end;
    finally
      DisplayServer.Contexts.UnlockList;
    end;
  result := true;
end;

 

Thanks to all developers for their help and assistance.

Share this post


Link to post
17 hours ago, mvanrijnen said:

probably your memo is getting "full", try to limit the total lines in the memo to for example max. 1000lines, and do the update between beginupdtae and  endupdate.

This will slowdown the app because of Memo performance, I use Selection for this

  if mLog.Lines.Count > 2000 then
  begin
    mLog.Lines.BeginUpdate;
    // Deleting lines one by one is damn slow.
    // So we take length of text and cut half of it
    mLog.SelStart := 0;
    mLog.SelLength := mLog.GetTextLen div 2;
    mLog.SelText := '';
    // Remove probably partial line
    mLog.Lines.Delete(0);
    mLog.Lines.EndUpdate;
  end;

 

11 hours ago, msd said:

cntClient := TIdContext(cliList);

This looks suspicious, shouldn't it be cliList [ i ]?

Edited by Fr0sT.Brutal

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×