Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Dec : Re: IdTCPServer
| Subject: | Re: IdTCPServer |
| Posted by: | "Remy Lebeau (TeamB)" (no.spam@no.spam.com) |
| Date: | Fri, 29 Dec 2006 12:29:47 |
"Anders Balslev" <itq@business.tele.dk> wrote in message
news:45957531$1@newsgroups.borland.com...
> When for example 3 client connections are connected to the
IdTCPServer
> (and the TCP Server has detected the IP adresses, IP1, IP2 IP3), how
> can I in the application send "Hello World" to IP2? - and something
else to
> IP3, and something else to IP1
Each client is represented by a TIdPeerThread (Indy 9) or TIdContext
(Indy 10) object within the server. Simply write whatever you want to
that object's Connection.
> which are NOT responses from the client- all 3 just remains open
TIdTCPServer is a multi-threaded component. You are supposed to do
your reading and writing for each client inside the OnExecute event,
which is triggered in the context of a worker thread for each client.
However, it does not sound like you are trying to implement a typical
client/server model in the first place. If your server is never going
to read from a client, only write to it, then you have a couple of
options:
1) put a Sleep() inside the OnExecute event and nothing else (to
prevent high CPU usage) and then use the server's Threads (Indy 9) or
Contexts (Indy 10) collection to directly access each client from
another thread (such as the main thread) when needed. For example:
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
begin
Sleep(50);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
List: TList;
begin
List := IdTCPServer1.Threads.LockList;
try
TIdPeerThread(List[SomeIndex]).Connection.WriteLn('Hello
World');
finally
IdTCPServer1.Threads.UnlockList;
end;
end;
Alternatively:
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
begin
// discard anything the client sends ...
if AThread.Connection.ReadFromStack(True, 50, False) > 0 then
AThread.Connection.InputBuffer.Clear;
end;
2) implement a per-client outbound queue that you can store data in
when needed, and then have the OnExecute event flush the queue to a
client regularly as needed.
uses
IdThreadSafe;
type
TMyPeerThread = class(TIdPeerThread)
public
constructor Create(ACreateSuspended: Boolean = True);
override;
destructor Destroy; override;
Queue: TIdThreadSafeStringList;
end;
constructor TMyPeerThread.Create(ACreateSuspended: Boolean =
True);
begin
Queue := TIdThreadSafeStringList.Create;
inherited Create(ACreateSuspended);
end;
destructor TMyPeerThread.Destroy;
begin
Queue.Free;
inherited Destroy;
end;
constructor TForm1.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
IdCPServer1.ThreadClass := TMyPeerThread;
end;
procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread);
var
Strings: TStrings;
begin
with TMyPeerThread(AThread) do
begin
Strings := Queue.Lock;
try
Connection.WriteStrings(Strings);
finally
Queue.Unlock;
end;
// discard anything the client sends ...
if Connection.ReadFromStack(True, 50, False) > 0 then
Connection.InputBuffer.Clear;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
List: TList;
begin
List := IdTCPServer1.Threads.LockList;
try
TMyPeerThread(List[SomeIndex]).Queue.Add('Hello World');
finally
IdTCPServer1.Threads.UnlockList;
end;
end;
Gambit
none