Newsgroups : Borland : borland.public.delphi.internet.winsock : 2008 Mar : Re: How to limit number of concurrent clients in TServerSocket?

www.cryer.info
Managed Newsgroup Archive

Re: How to limit number of concurrent clients in TServerSocket?

Subject:Re: How to limit number of concurrent clients in TServerSocket?
Posted by:"Bo Berglund" (bo.berglu..@system3r.se)
Date:Thu, 27 Mar 2008 10:41:43

On Wed, 26 Mar 2008 17:03:38 -0700, "Remy Lebeau \(TeamB\)"
<no.spam@no.spam.com> wrote:

>
>"Bo Berglund" <bo.berglund@telia.com> wrote in message
>news:r2hlu39tkk03t6p2tn9k9aoomrl9evt7lp@4ax.com...
>
>> My problem is that apparently the server is *not* operating "properly"
>
>You are not using it properly in your code.  Trust me, TServerSocket is very
>stable, and has been for years.  Problems that arise from it are almost
>always caused by errors in the user's code that is using the component
>incorrectly.

I understand this completely...
But I did not understand how I can get any communication to multiple
clients isolated to them unless I did some tricks like passing the
socket to a handler created on connection and then using this for
communications.


>> The handler assigns OnSocketEvent and OnSocketError handlers
>> to the passed socket and also saves it in a local field variable FSocket.
>
>DO NOT do that.  You are overwritting TServerSocket's internal event
>handlers that it assigns to each TCustomWinSocket object it creates.  No
>wonder your server is not working properly.  You are not allowing
>TServerSocket to react to disconnects, so it cannot fire the
>OnClientDisconnect event or destroy the TCustomWinSocket object (which is
>why the ActiveConnections count does not decrement).  You need to use the
>published events that TServerSocket itself exposes to you.  Do not use the
>TCustomWinSocket's events directly at all.  You need to redesign your code
>so your TClientComm class does not assign handlers to the TCustomWinSocket
>events directly.  For example:
>
>    procedure TRemoteServer.sckServerClientConnect(Sender: TObject; Socket:
>TCustomWinSocket);
>    var
>        i: integer;
>        Comm: TClientComm;
>    begin
>        try
>            i := sckServer.Socket.ActiveConnections;
>            if i > 1 then
>            begin
>                Log('Connection attempted with client already connected.');
>                Socket.Close;
>                Exit;
>            end;
>            Log('Client connected, IP=' + Socket.RemoteAddress + ' Host=' +
>Socket.RemoteHost);
>            Comm := TClientComm.Create(Socket, FRemoteServer);
>            try
>                FRemoteServer.ClientCallback := Comm.ClientCallback;
>                Log('Initializing new Client');
>                Comm.Initialize;
>            except
>                Comm.Free;
>                raise;
>            end;
>            Socket.Data := Comm;

OK, so I have to assign the communications object to a "Data" property
of the socket on connect (after the object has been created). I guess
that this in order to use it later for stuff like the disconnect
(below)?

>            Log('Socket communication channel opened to ' +
>Socket.RemoteAddress + ' Host='  + Socket.RemoteHost);
>        except
>            on E: Exception do
>                Log('Exception during client connect: ' + E.Message);
>        end;
>    end;
>
>    procedure TRemoteServer.sckServerClientDisconnect(Sender: TObject;
>Socket: TCustomWinSocket);
>    begin
>        if Socket.Data <> nil then
>        begin
>            TClientComm(Socket.Data).Disconnect;

OK, I get the idea here. I would just call the communications object's
method for disconnect (if any) and proceed.
In fact maybe this is where I should destroy the object as well? Like
so:
             TClientComm(Socket.Data).Free;

>            FRemoteServer.ClientCallback := nil;
>            Log('Socket communication closed: ' + Socket.RemoteAddress);
>        end;
>    end;
>
>    procedure TRemoteServer.sckServerClientError(Sender: TObject; Socket:
>TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer);
>    begin
>        // respond to the error as needed...
>        // use TClientComm(Socket.Data) as needed, if assigned...
>    end;

Remains to figure out what to do about the data between client and
server. If I assign the Socket.OnSocketEvent in order to *internally*
in the Comm object handle the incoming data, then I am defeating the
way you say I must *not* assign different handlers to the socket?

In the TServerWinSocket I only find events like OnClientRead and
OnClientWrite with a very unhelpful D7 Help entry (both events have
the same help text even though they clearly perform completely
different functions).

Should I implement the OnClientRead event to retrieve the incoming
data in this fashion maybe:

procedure TRemoteServer.sckServerClientRead(Sender: TObject; Socket:
TCustomWinSocket);
begin
  if Socket.Data <> nil then
    TClientComm(Socket.Data).OnReadData; {<= method to receive data}
end;

I assume that I can use the passed socket *inside* the Comm object to
send data to the client? Something like this:

procedure TClientComm.SendData(Data: string);
begin
  FSocket.SendText(Data)
end;

If I do this will the TServerSocket then behave sanely?

(And thank you for your patience!)


Bo Berglund

Replies:

In response to:

www.cryer.info
Managed Newsgroup Archive