Newsgroups : Borland : borland.public.delphi.internet.winsock : 2008 Mar : 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