* * *

Author Topic: Linux-Lazarus-Indy  (Read 2257 times)

scasparz

  • New member
  • *
  • Posts: 29
Linux-Lazarus-Indy
« on: June 28, 2018, 03:04:06 am »
Not sure if this is the proper place to put this, but I would like to give it a try. Please Mod forgive me if I erred.

Am using Linux Mint 18.3-64 XFCE, Lazarus 1.8.4 with FPC 3.0.4-3. Trying to break into the TCP world using Indy for Lazarus. Have downloaded Indy version 10.2.0.3 and installed it into Lazarus without issues.

Have located a number of trivia Indy examples at https://github.com/tinydew4/indy-project-demos/tree/master/TCPIP%20Delphi%20%26%20Indy10%20Client%20Server%20Demo.

Have started with the simplest one, that is the first 1_Sample simple string exchange. In this the author provides an elementary TCP client sending a string to an elementary TCP server. Understand this was written for the Indy-Delphi-Windows version. Have managed to port the client one to Linux without significant issues. There are some minimal differences, was not hard to modify. Of course remembered to add the indy path to the Lazarus Project unit path.

Had significant issues trying to port the server demo though. To begin with there seems no way to get the tIdTCPServer widget from the palette and drag it on my form, as this can crash my Lazarus.

Did not give up though. Declared an IdTCPServer property on my form, had it created manually at the Form OnCreate event handler, so far so good. Eg.
Code: Pascal  [Select]
  1. procedure TStringServerForm.FormCreate(Sender: TObject);
  2. begin
  3.   IdTCPServer1 := tIdTCPServer.Create(Self);
  4.   IdTCPServer1.Name := 'IdTCPServer1';
  5.   IdTCPServer1.Active := False;
  6.   IdTCPServer1.ListenQueue := 15;
  7.   IdTCPServer1.MaxConnections := 0;
  8.   IdTCPServer1.ReuseSocket := rsOSDependent;
  9.   IdTCPServer1.TerminateWaitTime := 5000;
  10.   // there is no nagle property available for Linux
  11.  
  12.   IdTCPServer1.Bindings.Add.IP   := '127.0.0.1';
  13.   IdTCPServer1.Bindings.Add.Port := 6000;
  14.   IdTCPServer1.OnConnect := IdTCPServer1Connect;
  15.   IdTCPServer1.OnDisconnect := IdTCPServer1Disconnect;
  16.   IdTCPServer1.OnException := IdTCPServer1Exception;
  17.   IdTCPServer1.OnExecute := IdTCPServer1Execute;
  18. end;
The above runs fine to the end. Yet there does not seem to be a way to activate server with the:
Code: Pascal  [Select]
  1. IdTCPServer1.Active := True
command, which raises an exception and terminates the server app.
 
Still did not give up. Transfered the server demo app to a virtual Windows 7 running Delphi XE which comes with Indy 10 installed. In this case the server demo app worked to a point. I mean I could send a string in Latin from the Mint-Lazarus demo-client-app to the Windows-Delphi demo-server-app, but I could not find a way to include international characters to the string. Believe this must be a transliteration issue. AFAIK Linux uses UTF8 while Redmond uses UTF16. Have used:
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(TIdTextEncoding.UTF8);
to get the string on the server at the IdTCPServer1Execute OnExecute handler, while similarly I used
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, enDefault);
at the client to send the string. This did not work. Had some better luck using
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, enUTF8);
at the client side. While Latin text comes OK, still have failed with international (Greek) chars.
In any case, each and every time I disconnect the client, the server fires the OnException event with message ‘Connection closed gracefully’. Is this an exception really?

To summarize:
1. Is there a newer more stable Indy version for Lazarus-Linux and where to get it from? Similarly are there any specific tweaks that should be done during the Indy installation on Lazarus, other than the usual (eg compile the .lpk twice)?
2. Is there any hope to drag the TCPServer widget from the palette onto the Lazarus form without crashing Lazarus?
3. Is there a way to activate my TCPServer instance on Linux-Lazarus without crashing the app?
4. Is there a way to have the correct transliteration with international character sets between a client and a server? In any case this I believe is a secondary issue as I do not plan a Linux to Windows connection but for educational use only.

and perhaps the most important of them all:
5. Do I stand a chance with Linux-Lazarus-Indy or should I have to look elsewhere? Indy is highly reputable and would be glad in case I could overcome my issues. On the other hand Windows and Delphi are not an option other than for fooling around.

Thanks for your time in advance.

s
« Last Edit: June 28, 2018, 03:07:41 am by scasparz »

denver

  • Jr. Member
  • **
  • Posts: 65
Re: Linux-Lazarus-Indy
« Reply #1 on: June 28, 2018, 07:54:29 am »
In Linux Version of Indy10, you need to confirm the IPVersion ( id_IPV4 or id_IPv6 )

IdTCPServer1.Bindings.Items[ 0 ].IPVersion := Id_IPv4 ;


GetMem

  • Hero Member
  • *****
  • Posts: 3085
Re: Linux-Lazarus-Indy
« Reply #2 on: June 28, 2018, 08:32:16 am »
Quote
To summarize:
1. Is there a newer more stable Indy version for Lazarus-Linux and where to get it from? Similarly are there any specific tweaks that should be done during the Indy installation on Lazarus, other than the usual (eg compile the .lpk twice)?
2. Is there any hope to drag the TCPServer widget from the palette onto the Lazarus form without crashing Lazarus?
3. Is there a way to activate my TCPServer instance on Linux-Lazarus without crashing the app?
4. Is there a way to have the correct transliteration with international character sets between a client and a server? In any case this I believe is a secondary issue as I do not plan a Linux to Windows connection but for educational use only.

and perhaps the most important of them all:
5. Do I stand a chance with Linux-Lazarus-Indy or should I have to look elsewhere? Indy is highly reputable and would be glad in case I could overcome my issues. On the other hand Windows and Delphi are not an option other than for fooling around.
Just install the latest version. Most of the issues mentioned above are fixed. You can download the latest version from here: https://svn.atozed.com:444/svn/Indy10 (use a svn client). Alternatively you can install indy with OPM(http://wiki.freepascal.org/Online_Package_Manager)

scasparz

  • New member
  • *
  • Posts: 29
Re: Linux-Lazarus-Indy
« Reply #3 on: June 29, 2018, 04:57:37 am »
To begin with many thanks for your kind responses.

Have installed a new vbox installation of Linux Mint 18.2, with FPC 3.0.4-3 and Lazarus 1.8.4. Have test it, got no issues.

Then downloaded Indy10 from http://packages.lazarus-ide.org (version 10.6.2.5457) as suggested by GetMem and have it installed again without issues . Newer version seems to work considerably better than the previous. I can now drag the tIdTCPServer component from the palette onto my form without breaking Lazarus.

Also have added the Id_IPv4 clause as suggested by Denver.

But I still fail to Activate IdTCPServer1 exactly as before with run time message 'RunError(232)'.
Not to mention that as I write code, I get the message:

Code: Text  [Select]
  1. Codetools, Errors: 1
  2. IdGlobal.pas(1889,105) Error: expected:; but deprecated found.
  3.  
  4. refering to line:
  5. GOffsetFromUTC: TDateTime = 0{$IFDEF HAS_DEPRECATED}{$IFDEF USE_SEMICOLON_BEFORE_DEPRECATED};{$ENDIF} deprecated{$ENDIF};
at the message window.

What am I doing wrong?
s
« Last Edit: June 29, 2018, 05:15:14 am by scasparz »

denver

  • Jr. Member
  • **
  • Posts: 65
Re: Linux-Lazarus-Indy
« Reply #4 on: June 29, 2018, 07:32:35 am »
To begin with many thanks for your kind responses.

But I still fail to Activate IdTCPServer1 exactly as before with run time message 'RunError(232)'.
Not to mention that as I write code, I get the message:

Code: Text  [Select]
  1. Codetools, Errors: 1
  2. IdGlobal.pas(1889,105) Error: expected:; but deprecated found.
  3.  
  4. refering to line:
  5. GOffsetFromUTC: TDateTime = 0{$IFDEF HAS_DEPRECATED}{$IFDEF USE_SEMICOLON_BEFORE_DEPRECATED};{$ENDIF} deprecated{$ENDIF};
at the message window.

What am I doing wrong?
s

For 'RunError(232)'. , you need to add   cthreads, as the first unit  in unit section in the main  .pas or  .lpr  in linux base and only one

Like this  :

uses
  {$DEFINE UseCThreads}
  {$IFDEF UNIX}{$IFDEF UseCThreads}
  cthreads,
  {$ENDIF}{$ENDIF}
  Interfaces, // this includes the LCL widgetset
  Forms ;

In the IdGlobal.pas, I just modify as follow and it work for me.

  GOffsetFromUTC: TDateTime = 0 ; deprecated ;

scasparz

  • New member
  • *
  • Posts: 29
Re: Linux-Lazarus-Indy
« Reply #5 on: June 30, 2018, 02:19:39 am »
Denver bingo!

Was with the wrong impression the Lazarus latest versions had been using cthreads by default. As you wrote it was exactly this the cause why I failed to activate the IdTCPServer. It now seems to work fine.

In regard to the statement:
Code: Pascal  [Select]
  1. GOffsetFromUTC: TDateTime = 0{$IFDEF HAS_DEPRECATED}{$IFDEF USE_SEMICOLON_BEFORE_DEPRECATED};{$ENDIF} deprecated{$ENDIF};
at the IdGlobal.pas, your suggestion to have it replaced with
Code: Pascal  [Select]
  1. GOffsetFromUTC: TDateTime = 0; deprecated;
did not work for me. On compiling Indy10 prior to installation Lazarus raises an error with message:
Code: Text  [Select]
  1. IdGlobal.pas(1889,44) Fatal: Syntax error, ":" expected but ";" found
Had never used the deprecated directive before. Tried to experiment a bit, used Lazarus to open a new trivia project where I declared a variable using identical syntax:
Code: Pascal  [Select]
  1. var
  2.   Form1: TForm1;
  3.   pap: Integer; deprecated;
and Lazarus raised exactly the same error again. Tried this on Delphi XE and once more got exactly the same error with the same message. Could not find some additional documentation either on the Delphi XE help subsystem or on the internet over deprecated. Am left with the impression -please correct me if wrong- that this directive only works with procedures or methods but not with variables. Consequently the only way I could find to avoid that error was to modify IdGlobal.pas omitting deprecated completely, eg:
Code: Pascal  [Select]
  1. GOffsetFromUTC: TDateTime = 0;
It is my understanding this was a bit arbitrary, nevertheless now not only Indy compiles without issues, but post installation codetools seems to work fine as well, allowing me for example to type in methods or properties the lazy way. This did not seem to work before by virtue of deprecated.

Looks like I now have a working Indy at least for elementary work. More important it looks like the package evolves as I have some serious expectations from it. Will keep experimenting on the TCP using Indy. Many thanks for your kind help. Without you and GetMem, I simply couldn't have done it.

best regards
s
« Last Edit: June 30, 2018, 02:26:45 am by scasparz »

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 426
    • Lebeau Software
Re: Linux-Lazarus-Indy
« Reply #6 on: July 02, 2018, 12:22:29 am »
Have downloaded Indy version 10.2.0.3 and installed it into Lazarus without issues.

Why such an OLD version?  The CURRENT version is 10.6.2(.5462).

Code: [Select]
  IdTCPServer1.Bindings.Add.IP   := '127.0.0.1';
  IdTCPServer1.Bindings.Add.Port := 6000;

Typical newbie mistake, usually due to bad 3rd party examples.  You are adding *2* bindings to the collection, one for 127.0.0.1:0, and the other for 0.0.0.0:6000.  You want to add only *1* binding, for 127.0.0.1:6000:

Code: [Select]
Binding := IdTCPServer1.Bindings.Add;
Binding.IP   := '127.0.0.1';
Binding.Port := 6000;

Or:

Code: [Select]
with IdTCPServer1.Bindings.Add do
begin
  IP   := '127.0.0.1';
  Port := 6000;
end;

I mean I could send a string in Latin from the Mint-Lazarus demo-client-app to the Windows-Delphi demo-server-app, but I could not find a way to include international characters to the string. Believe this must be a transliteration issue. AFAIK Linux uses UTF8 while Redmond uses UTF16.

Indy's default text encoding is actually US-ASCII, unless you explicitly specify otherwise, either by:

- setting the global GIdDefaultTextEncoding variable in the IdGlobal unit.

- setting the TIdIOHandler.DefStringEncoding property (and TIdIOHandler.DefAnsiEncoding property in pre-Unicode compilers).

- specifying an encoding parameter on a per-read/write operation basis.

Have used:
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(TIdTextEncoding.UTF8);
to get the string on the server at the IdTCPServer1Execute OnExecute handler, while similarly I used
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, enDefault);
at the client to send the string. This did not work.

Because you are mixing encodings, since enDefault is US-ASCII by default.  If you replace enDefault with enUTF8, it should then work OK.  Or, you can configure enDefault to be UTF-8 by setting the IdGlobal.GIdDefaultTextEncoding variable to encUTF8.

Had some better luck using
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, enUTF8);
at the client side.

Yes, exactly.

While Latin text comes OK, still have failed with international (Greek) chars.

UTF-8 works fine for the entirety of Unicode, Greek and all.

In any case, each and every time I disconnect the client, the server fires the OnException event with message ‘Connection closed gracefully’. Is this an exception really?

Yes, that is normal behavior.  Indy uses exceptions for error handling and notifications.  In a TIdTCPServer, when a client disconnects, subsequent read/write operations on that connection will raise an exception, which you should let TIdTCPServer catch and handle for you so that it can close the socket and clean up the worker thread that was managing that socket.

1. Is there a newer more stable Indy version for Lazarus-Linux and where to get it from?

Yes.  Links are on Indy's website:

http://www.indyproject.org/Sockets/Docs/Indy10Installation.aspx

http://www.indyproject.org/Sockets/Download/DevSnapshot.aspx

Indy is also available in Lazarus's "Online Package Manager" (OPM).

2. Is there any hope to drag the TCPServer widget from the palette onto the Lazarus form without crashing Lazarus?

This is the first that I'm hearing that it crashes like that.  Do you have any information about the actual crash?

3. Is there a way to activate my TCPServer instance on Linux-Lazarus without crashing the app?

Fix the way you are initializing the server's Bindings.

4. Is there a way to have the correct transliteration with international character sets between a client and a server?

Make sure you are using the same text encoding on both sides.

5. Do I stand a chance with Linux-Lazarus-Indy or should I have to look elsewhere?

Plenty of FPC users are using Indy in Linux.  And more users to come in the future as the latest Delphi (and upcoming C++Builder) now supports Linux development, too.

In Linux Version of Indy10, you need to confirm the IPVersion ( id_IPV4 or id_IPv6 )

IdTCPServer1.Bindings.Items[ 0 ].IPVersion := Id_IPv4 ;

Id_IPv4 is the default, unless specified otherwise, either explicitly with the IPVersion property, or implicitly by recompiling Indy with {$DEFINE IdIPv6} enabled in IdCompilerDefines.inc.

You can download the latest version from here: https://svn.atozed.com:444/svn/Indy10 (use a svn client).

Or the nightly ZIPPED version of the latest SVN revision at https://indy.fulgan.com/ZIP/.

But I still fail to Activate IdTCPServer1 exactly as before with run time message 'RunError(232)'.

Did you fix your incorrect Bindings setup, as described above?

Not to mention that as I write code, I get the message:

Code: Text  [Select]
  1. Codetools, Errors: 1
  2. IdGlobal.pas(1889,105) Error: expected:; but deprecated found.
  3.  
  4. refering to line:
  5. GOffsetFromUTC: TDateTime = 0{$IFDEF HAS_DEPRECATED}{$IFDEF USE_SEMICOLON_BEFORE_DEPRECATED};{$ENDIF} deprecated{$ENDIF};
at the message window.

Refer to past discussions on this forum about that issue.  The USE_SEMICOLON_BEFORE_DEPRECATED conditional was supposed to address that very issue.  Are you saying it is broken AGAIN?  USE_SEMICOLON_BEFORE_DEPRECATED was specifically added for FPC, which handles that line (and 1 other line, in IdWship6.pas) differently than Delphi does.

In the IdGlobal.pas, I just modify as follow and it work for me.

  GOffsetFromUTC: TDateTime = 0 ; deprecated ;

Per past discussions, USE_SEMICOLON_BEFORE_DEPRECATED is defined only for FPC 2.4.4 - 2.6.1, as the issue of the semicolon was supposedly fixed in 2.6.2 to allow the same syntax as Delphi (see below) (especially since Indy puts FPC into Delphi mode).  IdCompilerDefines.inc has this code:

Code: [Select]
{$IFDEF FPC}
  ...
  {$IFDEF FPC_2_4_4_OR_ABOVE}
    ...
    {$IFNDEF FPC_2_6_2_OR_ABOVE}
      {$DEFINE USE_SEMICOLON_BEFORE_DEPRECATED} // TODO: which earlier versions require a semicolon?
    {$ENDIF}
  {$ENDIF}
  ...
{$ENDIF}

Had never used the deprecated directive before. Tried to experiment a bit, used Lazarus to open a new trivia project where I declared a variable using identical syntax:
Code: Pascal  [Select]
  1. var
  2.   Form1: TForm1;
  3.   pap: Integer; deprecated;
and Lazarus raised exactly the same error again. Tried this on Delphi XE and once more got exactly the same error with the same message.

Delphi, and modern FPC, do not require the extra semicolon:

Code: Pascal  [Select]
  1. var
  2.   pap: Integer deprecated;

That is why the semicolon is IFDEF'ed for earlier versions of FPC.

Could not find some additional documentation either on the Delphi XE help subsystem or on the internet over deprecated.

http://docwiki.embarcadero.com/RADStudio/en/Declarations_and_Statements_(Delphi)#Hinting_Directives

Am left with the impression -please correct me if wrong- that this directive only works with procedures or methods but not with variables.

Hinting directives, like deprecated, work with variables, too.  The only thing they don't work with is properties (sadly, since Indy has a quite few of those).

Many thanks for your kind help. Without you and GetMem, I simply couldn't have done it.

I'm late to this discussion, but keep in mind that I am Indy's primary developer, so if you have any issues with Indy, you can pass them along to me.  Also note that Indy has an issue tracker on GitHub: https://github.com/IndySockets/Indy/issues.
« Last Edit: July 02, 2018, 12:29:41 am by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6333
Re: Linux-Lazarus-Indy
« Reply #7 on: July 02, 2018, 10:19:10 am »
Code: [Select]
{$mode delphi}
var
  GOffsetFromUTC: TDateTime =0 deprecated ;

begin
end.
compiles for me in 2.6.2,2.6.4,3.0.2,3.0.4 and trunk

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 426
    • Lebeau Software
Re: Linux-Lazarus-Indy
« Reply #8 on: July 02, 2018, 07:18:58 pm »
Code: [Select]
{$mode delphi}
var
  GOffsetFromUTC: TDateTime =0 deprecated ;

begin
end.
compiles for me in 2.6.2,2.6.4,3.0.2,3.0.4 and trunk

Yes, that is the format that Indy uses in 2.6.2+.

Unlike with Delphi (which Indy supports all the way back to D5), Indy has little support for past FPC versions.  The goal is to prefer to support only recent versions, since FPC is open-source and relatively easy for users to update at will.
« Last Edit: July 02, 2018, 07:21:08 pm by Remy Lebeau »
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

scasparz

  • New member
  • *
  • Posts: 29
Re: Linux-Lazarus-Indy
« Reply #9 on: July 06, 2018, 04:34:48 am »
Many thanks for your kind response Remy.

As I wrote have downloaded a more recent version of Indy and indeed most of the early issues I had have now been addressed. For example I can now drag the tIdTCPServer from the component palette onto my form without crashing Lazarus, no need to further investigate topic. Again as suggested by Denver have activated cthreads and now the server app does not crash on server activation. Have omitted the
Code: Pascal  [Select]
  1. IdTCPClient1.IPVersion := Id_IPv4;
clause and indeed had no issues.

I understand your suggestion in regard to the newbie mistake and made the relevant correction on the server app, again this worked fine.
Also have used:
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, IndyTextEncoding_OSDefault);
to send a string from the client app and
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(IndyTextEncoding_OSDefault);
to get the client string on the server app and this works happily with international characters. However replacing IndyTextEncoding_OSDefault with IndyTextEncoding_UTF8 on both apps wouldn’t work. Seems unnecessary when both apps are running under the same OS.

Just for completion have tested again the Linux-Lazarus-Indy client app with the Windows-Delphi XE-Indy server app, this time using:
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(enUTF8);
at the windows server and it too worked as a breeze including international characters.

But I still have issues each time I disconnect the client from the server. On Linux, both the server and the client app raise an exception. But while on the server app I can handle this with the OnException event, I have failed to find a way to do the same client side.

I understand perfectly the reasons you have provided as to why this exception is raised and again I understand this exception is raised from deeply into the Indy code. Have tried a call to IdTCPClient1.CheckForGracefulDisconnect(False) before calling IdTCPClient1.Disconnect without success. Have also tried  IdTCPClient1.Disconnect(False) again with no success.
 
On this topic, one noticeable difference between the Linux-Lazarus-Indy-Server App and the Windows-Delphi XE-Indy-Server app has been that when closing the connection from the Linux-Lazarus-Indy-Client App the same exception is raised on the server side, yet it is not raised on the Lazarus client side.

Presume there must be some better way to close the connection from the client both graciously and without raising this exception but have failed to find it. How should I close the client-side connection without all this fuzz?

One last question please: I understand the tIdTCPServer has to be multi-threaded as multiple connections are supposed to be made against it from a number of clients. However is the tIdTCPClient multi threaded too? Should I have to make thread-safe calls?

As I wrote on my previous posts had considerable difficulties to start with Indy on Lazarus. Things are getting much better after a couple of posts on this forum. Indy is a great package and am glad to notice the more I use it the more I find it workable from Linux/Lazarus as well. Hope to get the same dynamics on Lazarus as it already has with Delphi. 

As a last note, have taken a look on the deprecated directive and your syntax is absolutely correct. In that sense, my assumption that deprecated cannot be used on variables was completely wrong.


regards
s

marcov

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 6333
Re: Linux-Lazarus-Indy
« Reply #10 on: July 06, 2018, 11:14:46 am »
Yes, that is the format that Indy uses in 2.6.2+.

Unlike with Delphi (which Indy supports all the way back to D5), Indy has little support for past FPC versions.  The goal is to prefer to support only recent versions, since FPC is open-source and relatively easy for users to update at will.

From what I see use below 2.6.4. is rare.   While one occasionally sees old versions they are mostly because of the versions in LTS versions of Linux.

Occasionally also win9x holdolds and people that get the version from their education institution. (which don't renew the course every year)

Remy Lebeau

  • Sr. Member
  • ****
  • Posts: 426
    • Lebeau Software
Re: Linux-Lazarus-Indy
« Reply #11 on: July 06, 2018, 09:02:03 pm »
Also have used:
Code: Pascal  [Select]
  1. IdTCPClient1.IOHandler.WriteLn(Edit1.Text, IndyTextEncoding_OSDefault);
to send a string from the client app and
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(IndyTextEncoding_OSDefault);
to get the client string on the server app and this works happily with international characters.

That entirely depends on the particular charset locale that the OS uses, which is very machine-dependent and user-dependent.  It is really not a good idea to use OSDefault for network communications, especially once you start dealing with communications between multiple machines.  You really should be using UTF-8 instead.  OSDefault is lossy, UTF-8 is not.

However replacing IndyTextEncoding_OSDefault with IndyTextEncoding_UTF8 on both apps wouldn’t work.

Works fine for me, on Windows at least.  I don't use Linux.  Maybe there is a bug in Indy's implementation of UTF-8 on Linux? Indy uses platform-specific APIs (Win32 on Windows, libiconv on Linux) for most of its charset handling.  But there are some quirks in how libiconv works, particularly in how Indy calculates the FMaxCharSize and FIsSingleByte members of TIdTextEncodingBase.  So, all I can say is try to debug into Indy's source code and see if TIdUTF8Encoding is misbehaving on Linux.

Seems unnecessary when both apps are running under the same OS.

Even under the same OS, the OSDefault locale may be different between machines.  So you should stay away from OSDefault.

Just for completion have tested again the Linux-Lazarus-Indy client app with the Windows-Delphi XE-Indy server app, this time using:
Code: Pascal  [Select]
  1. LLine := AContext.Connection.IOHandler.ReadLn(enUTF8);
at the windows server and it too worked as a breeze including international characters.

So the problem is only in reading UTF-8 on Linux, not with sending UTF-8?

But I still have issues each time I disconnect the client from the server. On Linux, both the server and the client app raise an exception.

That is normal behavior.

But while on the server app I can handle this with the OnException event, I have failed to find a way to do the same client side.

Because there is no event for it.  You will have to wrap your socket I/O operations inside of try/catch blocks.

I understand perfectly the reasons you have provided as to why this exception is raised and again I understand this exception is raised from deeply into the Indy code. Have tried a call to IdTCPClient1.CheckForGracefulDisconnect(False) before calling IdTCPClient1.Disconnect without success.

Calling CheckForGracefulDisconnect() like that doesn't serve any useful purpose.

Have also tried  IdTCPClient1.Disconnect(False) again with no success.

Disconnect() should not be raising an exception.  Are you saying it does?  Write() and Read...() certainly can.

On this topic, one noticeable difference between the Linux-Lazarus-Indy-Server App and the Windows-Delphi XE-Indy-Server app has been that when closing the connection from the Linux-Lazarus-Indy-Client App the same exception is raised on the server side, yet it is not raised on the Lazarus client side.

What is the EXACT exception that you are seeing?  From which code?  Can you be more specific?

Presume there must be some better way to close the connection from the client both graciously and without raising this exception but have failed to find it. How should I close the client-side connection without all this fuzz?

Calling Disconnect() is the correct way.  If it is failing, something is wrong that needs to be fixed.

One last question please: I understand the tIdTCPServer has to be multi-threaded as multiple connections are supposed to be made against it from a number of clients. However is the tIdTCPClient multi threaded too?

No, it is not.  Most of Indy's components are not multi-threaded, they operate in whatever thread your code uses them in.  Only TCP/UDP servers, a few clients (TIdTelnet, TIdCmdTCPClient, TIdIPMCastClient) and a couple of utility components (TIdIPWatch, TIdIPAddrMon) are multi-threaded.

Should I have to make thread-safe calls?

That entirely depends on how you use it in your code.
Remy Lebeau
Lebeau Software - Owner, Developer
Internet Direct (Indy) - Admin, Developer (Support forum)

scasparz

  • New member
  • *
  • Posts: 29
Re: Linux-Lazarus-Indy
« Reply #12 on: July 13, 2018, 05:04:57 am »
Remy sorry for being late to answer, had an awful lot of homework to do.

In regard to the on disconnect exception, which I believed it was raised also client-side it was my fault. It does not. I used to execute two Lazarus instances on separate workspace screens, one for the server and one for the client app. I used to be on client workspace disconnecting the client from the server, this exception was risen on the server only, but Linux brought it to me at the client workspace, atop the client app, which made me believe erroneously it originated from the client rather than from the server. My bad, apologies for this confusion. Was exactly this the reason why I though I could not see this exception client wise, when it was disconnecting from a virtual windows server running Delphi-Indy. Apparently there are no issues there. And client-wise Disconnect() is working fine to close a connection, nothing else is actually required, everything is by the book here.

Looks like enUTF8 appears to be deprecated now, Indy prefers the IndyTextEncoding_*() functions instead, at least on Linux.

I understand the use of IndyTextEncoding_UTF8() should work for Linux and that it is the choice of preference, however for some reason it seems it doesn’t not work. Looks the problem arises client side, as it is the client app that freezes while the server one appears as not getting anything.

Have tried a number of permutations, still the only way I managed to pass international characters on Linux has been with the use of IndyTextEncoding_OSDefault() on both the client and the server app. Yes, it may not really be a good idea, still it is the only working one I could find on Linux.

Have managed to pass a Stream, had a lot of difficulties, until I read the example at https://github.com/tinydew4/indy-project-demos/tree/master/TCPIP%20Delphi%20%26%20Indy10%20Client%20Server%20Demo/4_sample%20Stream%20Exchange, and realize the use of buffered writes.

One very simple question in case you have the time:
It is my understanding that to pass a stream I have to start by sending server the stream size first, then the actual stream so that the server will know the size of the stream to read. In the example that saved my life, the author sends the size, then he ignites a buffered write by calling WriteBufferOpen that is before he sends the stream itself. Is this the correct way? Or should I have to make a call to WriteBufferOpen before I do anything else, such as this?
Code: Pascal  [Select]
  1.   IdTCPClient1.IOHandler.WriteBufferOpen;
  2.   IdTCPClient1.IOHandler.Write(MemoryStream.Size); // send size
  3.   IdTCPClient1.IOHandler.Write(MemoryStream, MemoryStream.Size); // send stream
  4.   IdTCPClient1.IOHandler.WriteBufferFlush;
  5.   IdTCPClient1.IOHandler.WriteBufferClose; // close buffered write

I appreciate you bothered to answer multiple questions from the ignorant me. Many thanks again.


kind regards
s
« Last Edit: July 13, 2018, 05:12:14 am by scasparz »

denver

  • Jr. Member
  • **
  • Posts: 65
Re: Linux-Lazarus-Indy
« Reply #13 on: July 13, 2018, 08:02:06 am »

In regard to the on disconnect exception, ....


You have to try to handle the IdTCPServer1Disconnect(AContext: TIdContext) event to prevent disconnect except.

If you want to send any kind of data between TIdTCPServer and TidTCPClient, I have a very simple component that work for you. It passes Strings, Integer, DateTime, Blob,even dataset ( Modified TBufDataSet ) between  TIdTCPServer and TidTCPClient at the following link :

https://github.com/denverjen/LazarusMiddleWare

Happy programming ...  :D


scasparz

  • New member
  • *
  • Posts: 29
Re: Linux-Lazarus-Indy
« Reply #14 on: July 13, 2018, 08:52:46 pm »
Thanks denver. Have already downloaded it. Will definitely give it a shot!


kind regards
s

 

Recent

Get Lazarus at SourceForge.net. Fast, secure and Free Open Source software downloads Open Hub project report for Lazarus