Board index » delphi » Re: Connecting socket-based applications in a peer-to-peer local network

Re: Connecting socket-based applications in a peer-to-peer local network


2008-07-30 12:48:05 AM
delphi201
"Enquiring Mind" <XXXX@XXXXX.COM>writes
Quote
A point you seem to be making is that if the operating system only
supports single-threaded applications, as I think you said was the
case before Windows 95, then you cannot use blocking socket I/O
without blocking the whole application so you must use non-blocking
socket I/O instead.
I was pointing out that Windows 3.x itself did not have any notion of
threads. Running a blocking operation in an application could freeze the
entire OS. That was no longer the case when Windows 95 was introduced.
Nobody targets Windows 3.x anymore, so don't worry about it.
Quote
However with non-blocking sockets I'd have thought that you still
need a separate thread for every socket connection blocking I/O function
call, but that the threads are now created and managed by the operating
system rather than by the application.
Not exactly. I suggest you read up on how overlapped I/O and completion
ports actually work:
Socket I/O
msdn.microsoft.com/en-us/library/ms740523(VS.85).aspx
Socket overlapped I/O versus blocking/nonblocking mode
support.microsoft.com/kb/181611
Overlapped I/O and Event Objects
msdn.microsoft.com/en-us/library/ms740087.aspx
msdn.microsoft.com/en-us/library/aa923630.aspx
Synchronous and Asynchronous I/O
msdn.microsoft.com/en-us/library/aa365683.aspx
I/O Completion Ports
msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx
Quote
If one uses a TTcpServer component to handle client socket connections,
then to achieve maximum internet-style scalability with blocking socket
I/O
it should suffice to limit the life of the thread created for the
connection to just the duration of a single request .
Not really. Repeatedly creating and tearing down threads has quite a bit of
overhead to it, especially the shorter the time each thread runs for. If
you are going to use such a model, then thread pooling would be a better
choice.
Quote
For example:
TTcpServer (and TServerSocket) uses thread pooling internally.
Quote
With this code the thread created to handle the client connection
is released shortly after the OnAccept event handler is exited
No, it is not. Look at the TTcpServer source code more carefully. The
thread calls the OnAccept event in a loop, one firing per client connection.
When the OnAccept handler exits, the thread loops back and processes the
next client connection, or goes to sleep if there is no pending client.
Gambit
 
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Remy Lebeau (TeamB)" <XXXX@XXXXX.COM>writes
Quote


I suggest you read up on how overlapped I/O and completion ports actually
work:
...
Thanks for the useful references.
To qualify the point I made in my previous post about the relative
computational efficiency of non-blocking versus blocking socket I/O, I can
see that non-blocking socket I/O would be more efficient than a
well-programmed blocking socket I/O if the processor that performs the
background socket I/O is not one of the main processors used directly by the
OS to process threads, but a dedicated I/O interface processor. The same
also applies to overlapped I/O.
To revise the point I made about the suitability of the TTcpClient and
TTcpServer components for non-blocking socket I/O, I can see that although
the components don't support the more advanced Winsock 2 non-blocking and
overlapped socket I/O facilities (i.e. the API functions prefixed by WSA), I
would have thought that they can still be used for non-blocking socket I/O
if the select method is used to wait for asynchronous I/O completion.
Quote

Not really. Repeatedly creating and tearing down threads has quite a bit
of overhead to it, especially the shorter the time each thread runs for.
If you are going to use such a model, then thread pooling would be a
better choice.

I know that a thread pool can be used to avoid the overhead of repeated
thread object creation and destruction. But the point I made about the
impact of the duration of each thread session on overall efficiency still
holds, I'd have thought, because the shorter the duration, the lower the
number of concurrently active threads.
Quote
>With this code the thread created to handle the client connection
>is released shortly after the OnAccept event handler is exited

No, it is not. Look at the TTcpServer source code more carefully. The
thread calls the OnAccept event in a loop, one firing per client
connection. When the OnAccept handler exits, the thread loops back and
processes the next client connection, or goes to sleep if there is no
pending client.

I was aware that TTcpServer uses a thread pool for client socket threads. By
'released', I didn't mean destroyed, but released from active service and
returned to the pool of inactive threads.
I have read in accounts of socket facilities provided by other languages
about the importance of calling the 'flush' function between a send and recv
call to ensure that socket I/O operation is completed and all data in the
socket's outgoing data stream buffer is sent down the line. I haven't found
a function by this name in the WinSock API, or in the Delphi components.
Does this mean that the send and recv Windows API functions automatically
take care of flushing the buffer?
Regards,
EM
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Enquiring Mind" <XXXX@XXXXX.COM>writes
Quote
I would have thought that they can still be used for non-blocking
socket I/O
They can be, otherwise the BlockMode property would not exist in the first
place.
Quote
I have read in accounts of socket facilities provided by other languages
about the importance of calling the 'flush' function between a send and
recv call to ensure that socket I/O operation is completed and all data
in the socket's outgoing data stream buffer is sent down the line.
There is no 'flush' function in the socket API. Once outbound data has been
passed to a socket, it is out of the application's hands. The socket sends
the data on its own time.
Quote
I haven't found a function by this name in the WinSock API, or in the
Delphi components.
Because there isn't one.
Gambit
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Remy Lebeau (TeamB)" <XXXX@XXXXX.COM>writes
I hope I am not making this thread go on too long - but it is an interesting
subject!
Quote

>I would have thought that they can still be used for non-blocking
>socket I/O


They can be, otherwise the BlockMode property would not exist in the first
place.

That's true, but the implementation of TBaseSocket class in the Sockets unit
doesn't seem to take into account the implications of the BlockMode property
on the validity of the code. Consider for example the method
function TBaseSocket.Receiveln(const eol: string): string;
As I see it, the method contains 2 conceptual errors:
Error 1) Since the code contains a call of Recv inside a loop, it probably
won't work if the socket is non-blocking, because it would not wait for the
completion of one Recv operation before proceeding to the next Recv
operation. Therefore the code should either check the blocking mode and
raise an exception if it is non-blocking, or else it should correctly handle
the non-blocking socket case and include some code to wait for the
completion of the Recv operation.
Error 2) The function's code previews ("peeks") the incoming stream in
chunks of 511 bytes or less, and searches the chunk for the termination
string "eol". If the termination string is found, then the function receives
the characters up to and including the end of the termination string and
terminates the loop, and if it isn't found, the function receives the whole
chunk and continues the loop. Thus 2 possible cases are considered: the
chunk of data in the socket's buffer either contains the termination string,
or it doesn't. But there is a third case not considered: the termination
string straddles 2 successive chunks. Should this case arise, the code would
not identify the end of string condition and the loop would not terminate
correctly.
All this leads me to think: wouldn't it be much better, and easier, if
Delphi simply provided a library of functions in Pascal syntax for the
Berkeley socket functions in the Windows API, as listed in the MS SDK help
files under "socket functions", and let the developer worry about thread
creation etc.? The library would be easily portable to any operating system
that supports the Berkeley socket model - i.e all the major OS's. Granted, a
developer could use the WinSock API functions directly - but the code would
be more readable and more portable if entirely in Pascal style.
It would also be nice if Delphi were to provide a library of data stream
I/O routines in Pascal syntax that support the MS asynchronous I/O model
(i.e. overlapped IO, synchronization objects, WaitForXXX functions, etc.).
These should be applicable without change to serial port data streams and
socket data streams. The conceptual model should be an abstract
time-discontinuous data stream accessed though a queued buffer. The
conceptual model should include notification of asynchronous I/O completion
by 4 methods: a) calling of an event handler b) posting a message c)
signalling a synchronization object d) calling a Windows completion routine.
The important thing is that the Delphi encapsulation should be in terms of
the abstract model, so that it can be readily ported to any OS whose API
supports asynchronous I/O. The data stream type could simply be an extended
type of file, that adds to the characteristics of the original Pascal file
type the concepts of access through a queue, asynchronous operation and
notification of completion.
I have noticed that both Java and C# provide socket routines that are
relatively close to the Berkeley socket model, and in both the socket
exposes input and output data streams that can be manipulated just like any
other data stream. If only Delphi could keep things equally simple!
EM
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Enquiring Mind" <XXXX@XXXXX.COM>writes
Quote
That's true, but the implementation of TBaseSocket class in the Sockets
unit doesn't seem to take into account the implications of the BlockMode
property on the validity of the code.
Pretty much everything in that unit do not take non-blocking into account
properly.
Quote
wouldn't it be much better, and easier, if Delphi simply provided a
library of
functions in Pascal syntax for the Berkeley socket functions in the
Windows
API, as listed in the MS SDK help files under "socket functions", and let
the
developer worry about thread creation etc.?
Look at the VCL's "WinSock" unit (which the "Sockets" and "Scktcomp" units
use internally).
Gambit
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Remy Lebeau (TeamB)" <XXXX@XXXXX.COM>writes
Quote

Not exactly. I suggest you read up on how overlapped I/O and completion
ports actually work:

Socket I/O
msdn.microsoft.com/en-us/library/ms740523(VS.85).aspx

Socket overlapped I/O versus blocking/nonblocking mode
support.microsoft.com/kb/181611

Overlapped I/O and Event Objects
msdn.microsoft.com/en-us/library/ms740087.aspx
msdn.microsoft.com/en-us/library/aa923630.aspx

Synchronous and Asynchronous I/O
msdn.microsoft.com/en-us/library/aa365683.aspx

I/O Completion Ports
msdn.microsoft.com/en-us/library/aa365198(VS.85).aspx

Following the guidelines in the above links, I have started looking into
writing some non-blocking socket I/O routines using WinSock API functions
like WSAWaitForMultipleEvents. But the first problem I have encountered is
that many of the WSAxxx API functions needed are not included in my version
of the Winsock unit (shipped with Delphi 7). I have checked dates on the
internet and have found that Winsock 2 was published a considerable time
before Delphi 7, so I was wondering why the omission. To add further to my
puzzlement is the fact that the Windows SDK help files shipped with my
version of Delphi do include the WSAxxx routines.
Are the WSAxxx routines to be found in some other unit, then?
Regards,
EM
 

Re: Connecting socket-based applications in a peer-to-peer local network

"Enquiring Mind" <XXXX@XXXXX.COM>writes
Quote
Following the guidelines in the above links, I have started looking into
writing some non-blocking socket I/O routines using WinSock API
functions like WSAWaitForMultipleEvents. But the first problem I
have encountered is that many of the WSAxxx API functions needed
are not included in my version of the Winsock unit (shipped with Delphi
7). I have checked dates on the internet and have found that Winsock 2
was published a considerable time before Delphi 7, so I was wondering why
the omission.
You would have to ask CodeGear that. The VCL has not been updated to use
WinSock 2 in any version. Not even Delphi 2007 has the functions declared.
Quote
To add further to my puzzlement is the fact that the Windows SDK help
files shipped with my version of Delphi do include the WSAxxx routines.
That has always been the case.
Quote
Are the WSAxxx routines to be found in some other unit, then?
No. You will have to declare them yourself, or find a third-party unit that
does it for you.
Gambit