Discussion:
Native Delphi support for Win32 sockets
(too old to reply)
Enquiring Mind
2008-07-10 13:46:40 UTC
Permalink
Hi,

I find it slightly bizarre that Delphi provides the native Delphi components
TTcpServer and TTcpClient for socket I/O, but Borland (aka Codegear aka
...) is said in books like Mastering Delphi 2005 to recommend the use of
Indy or other third party components instead. The criticism of the native
Delphi components goes back to the time they were first released (around the
time of Delphi 7 release), so surely Borland has had plenty of opportunities
to fix any real deficiencies in subsequent Delphi releases, or alternatively
explain to developers why the perceived deficiencies only exist due to
misunderstanding of the components. Misunderstanding is highly likely, due
to the sub-standard documentation. When I stepped through the on-line help
pages in the Contents section on socket components , I found that most had
general text book information about sockets but no Delphi-specific detail
and no examples, as if they had been written by someone not familiar with
the detail of the components. I also found that some pages stopped in mid
sentence, as if time had run out to do a proper job ! It makes it look as if
the developer of the components has left the company and there is nobody
left with the knowledge to fix the problem or produce adequate
documentation.

IMHO, since sockets are fundamental part of the operating system and of
applications, a rapid application development language that purports to
provide a high level interface to the operating system should cover Win32
sockets natively. There is a place for higher level components from third
parties, but the core library of the development language should provide a
high level interface to fundamental file-orientated socket operations that
is fully functional.

I have briefly studied the TTcpServer and TTcpClient components, and have
concluded that they can be used if only a few key points are explained (so
why are adequate explanations totally lacking in the D7 help files ? -
making these components possibly the worst covered in the whole of the D7
help files). Some of the issues that have come in for criticism in the NG's,
like the difficulty in overriding the TClientSocketThread.Execute method,
seem to me to be in fact non-issues. The fact that the Execute method is
declared in the public section of the TClientSocketThread class is a clear
indication that it is not intended to be overridden in descendent classes.
There are alternative ways of customising the Execute behaviour in a
descendent class, most notably by putting the work to be done in the
OnAccept event handler of the TTcpServer object.

Having said the TTcpServer and TTcpClient components are in actual fact
usable, I would nevertheless question the logic of their design.

1. The ownership relationship between the TClientSocketThread and
TCustomIpClient (client socket) objects seems to me to be the wrong way
round. The thread object owns the socket object, when it would make more
sense for the socket to own the thread. Why? Because when a new connection
is made, we need to create one and only one new client socket on the server,
which can then be used for file-orientated I/O just like a serial port. The
number of threads needed to handle the socket I/O depends on the application
and may need to be more than one - there are many situations where multiple
threads are needed to handle one socket. For example we could have one
thread to read messages from the socket and put them into a queue, another
to retrieve messages from the queue and write them to the socket, and a
third to handle the queue. However in the TtcpServer data structure the
list of current socket connections is represented by a list of
TClientSocketThread objects rather than by a list of TCustomIpClient
objects! A client socket object has to be retrieved from the
TClientSocketThread object that owns it.

2. In other languages (like Java) the Accept method of the server socket
returns a new client socket object, and it's then up to the application
program to create a thread object to handle the I/O through that socket, in
the same way that the application can create one or more threads to handle
I/O through a serial port file object. There is no need IMO for a socket to
be treated differently to any other asynchronous I/O channel. The Delphi
components seek to do too much thread management work behind the scenes, for
example fetching threads from a thread pool. The right place for this is in
a higher level class.

3. The TCustomTcpServer.OnAccept event handler runs in the
TClientSocketThread rather than in the TServerSocketThread thread where it
would seem to be more logical for it to run. I realise that this could block
the TServerSocketThread if the client socket that should be returned by the
OnAccept event contains some blocking code that is not in a separate
TClientSocketThread, but it would make the logic of the components much
clearer.

4. It would be preferable for a TCustomIpClient object to get a reference to
its associated TClientSocketThread object from a local field (assigned in
the constructor) rather than from a Threadvar variable. What's the reason
for using a threadvar variable?

5. The TServerSocketThread gives inadequate access to the collection of
threads it owns via the property:

property ThreadPool: TList read FThreadPool;

IMHO this is an example of very poor style for a property in a strongly
typed language, because a) an array rather than array component is returned,
thus creating opportunities for indexing errors; b) the array component type
is not defined, making a developer without access to the source code unable
to actually use the property safely. A much better interface would have
been:

property ThreadPoolComponentByIndex[Index]: TClientSocketThread read
GetThreadPoolComponentByIndex;

function GetThreadPoolComponentByIndex(Index: integer): TClientSocketThread;
begin
if (index<0) or Index>(FThreadPool.Count-1) then
raise exception.Create('...')
else
Result:= FThreadPool[Index] as TClientSocketThread;
end;

6. What does the following statement in TServerSocketThread.Destroy do?

while FThreadPool.Count > 0 do;

7. In TServerSocketThread.Execute what is the purpose of the statement?

Sleep(0);

8. In TCustomTcpServer.Open the function Listen, declared as taking one
parameter, is called without any parameters. Is this a valid Pascal
construct?

9. What is the purpose of the function TCustomTcpServer.Accept? It is not
called within the Sockets unit and internally creates a TCustomIpClient
object having an ownership that is incompatible with that of the
TCustomIpClient object created by the TClientSocketThread.Execute method.

10. The method TCustomTcpServer.Close contains the code
try
finally
LeaveCriticalSection(FThreadLock);
end;
What's the purpose of the empty try..finally construct?

TIA for any enlightenment on these tricky points.

EM
Remy Lebeau (TeamB)
2008-07-10 17:13:00 UTC
Permalink
Post by Enquiring Mind
I find it slightly bizarre that Delphi provides the native Delphi
components TTcpServer and TTcpClient for socket I/O
Those components were introduced as part of the CLX for Kylix. The VCL's
native socket components are TServerSocket and TClientSocket instead. The
CLX components are horribly implemented compared to the VCL components,
though.
Post by Enquiring Mind
but Borland (aka Codegear aka ...) is said in books like Mastering
Delphi 2005 to recommend the use of Indy or other third party
components instead.
TClientSocket and TServerSocket were deprecated when CodeGear started
bundling Indy with the IDE install. They are not installed by default
anymore. If you want to use them, you can install the dclSockets... package
manually.
Post by Enquiring Mind
The criticism of the native Delphi components goes back to the time they
were
first released (around the time of Delphi 7 release), so surely Borland
has had
plenty of opportunities to fix any real deficiencies in subsequent Delphi
releases
The design of TTcpClient and TTcpServer is poorly architectured. They
require a lot of extra work on the user's part that TServerSocket and
TClientSockt did not require. It would take a complete re-write to make
them usable, let alone to bring them up to par with the functionality that
the VCL components and/or third-party components provide. Considering that
CLX is dead anyway, I seriously doubt CodeGear will be putting any energy to
fix it. I wouldn't want them to anyway. Win32 VCL is where the real action
is for CodeGear still. Let the third party vendors provide the
cross-platform support.


Gambit
Enquiring Mind
2008-07-14 15:53:38 UTC
Permalink
Post by Remy Lebeau (TeamB)
Post by Enquiring Mind
I find it slightly bizarre that Delphi provides the native Delphi
components TTcpServer and TTcpClient for socket I/O
Those components were introduced as part of the CLX for Kylix. The VCL's
native socket components are TServerSocket and TClientSocket instead. The
CLX components are horribly implemented compared to the VCL components,
though.
I this just the general opinion of developers, or has the poor architecture
of these components been acknowledged by Codegear?
Post by Remy Lebeau (TeamB)
TClientSocket and TServerSocket were deprecated when CodeGear started
bundling Indy with the IDE install. They are not installed by default
anymore. If you want to use them, you can install the dclSockets...
package manually.
The design of TTcpClient and TTcpServer is poorly architectured. They
require a lot of extra work on the user's part that TServerSocket and
TClientSockt did not require. It would take a complete re-write to make
them usable, let alone to bring them up to par with the functionality that
the VCL components and/or third-party components provide. Considering
that CLX is dead anyway, I seriously doubt CodeGear will be putting any
energy to fix it. I wouldn't want them to anyway. Win32 VCL is where the
real action is for CodeGear still. Let the third party vendors provide
the cross-platform support.
Win32 includes WinSock socket support under the Windows OS. Therefore if
Codegear are focussing on providing the premier tool for developing Win32
applications, they should IMHO include a high level library to wrap WinSock.
Third party vendors can provide similar facilities for other operating
systems. I would personally like Codegear to take up the challenge and
update the Linux implementation. It doesn't depend on visual widgets, so
should probably work with very little modification. If we look at Java and
C#, both these language systems include support for socket programming. Can
Delphi be considered to be in the same league if it doesn't?

I have just completed an illustrative client-server application to test the
use TTcpServer and TTcpClient components. It wasn't easy, primarily on
account of the very poor documentation, and of the over-complex
architecture, but app nevertheless seems to satisfy its admittedly modest
objectives. It does exactly what it was designed to do, i.e just receive and
send text messages over multiple socket connections on a server, without
having to use Commands etc which seem to be needed when using the Indy
components.

As for the Indy components, I have them on my component palette, but I don't
see any help files for them installed in my Delphi help system. Where can
the help files be obtained and how can they be integrated into the Delphi
help system? If the Delphi installer installs the Indy components by default
on the component palette, why doesn't it do the complete job and install the
help files at the same time?

Regards,

EM
Remy Lebeau (TeamB)
2008-07-14 17:09:36 UTC
Permalink
Post by Enquiring Mind
I this just the general opinion of developers, or has the poor
architecture of these components been acknowledged by Codegear?
It is my personal opinion after looking at the actual implementation code
and trying to use the components. CodeGear implemented TTcpClient and
TTcpServer with a "lowest-common-denominator" approach in order to get it
running on both Windows and Linux. But that implement is much too low-level
for most users, and does not expose enough functionality to be very useful.
Third-party cross-platform socket libraries do a much better job of that.
Post by Enquiring Mind
Win32 includes WinSock socket support under the Windows OS. Therefore
if Codegear are focussing on providing the premier tool for developing
Win32 applications, they should IMHO include a high level library to wrap
WinSock.
They already did, and were doing for years - the TClientSocket and
TServerSocket components.
Post by Enquiring Mind
It does exactly what it was designed to do, i.e just receive and send text
messages over multiple socket connections on a server, without having to
use Commands etc which seem to be needed when using the Indy components.
Indy is a high-level TCP/IP wrapper. It does not require Commands in order
to exchange data, though that is one of the features it provides to easy
development.
Post by Enquiring Mind
Where can the help files be obtained and how can they be integrated into
the Delphi help system?
Look on Indy's website.


Gambit

Loading...