Watch, Follow, &
Connect with Us

For forums, blogs and more please visit our
Developer Tools Community.


Welcome, Guest
Guest Settings
Help

Thread: TIdTCPServer for communication



Permlink Replies: 10 - Last Post: Jul 3, 2014 12:38 PM Last Post By: Remy Lebeau (Te...
ehsan mohtadi

Posts: 10
Registered: 2/14/09
TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 27, 2014 9:34 AM
Hi
I have made an server with application as server with TIdTCPServer for accessing data recieved from about 200 client on one port .
I know each client has each thread . thease clients send data to server continusely .
Now i want to send data from server to these clients .
I don't know how to do it . i should this work with same socket that server receive with it or i should another socket for it .
i use execute event of IdTCPServer for receiving data . now i want to send some data to one client that are connected to server .
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 27, 2014 1:12 PM   in response to: ehsan mohtadi in response to: ehsan mohtadi
ehsan wrote:

Now i want to send data from server to these clients .

I don't know how to do it .

Examples of that have been posted many many times before, both in these forums
and in Indy's forums. Please search around. The jst of it is that you have
to loop through the TIdTCPServer.Contexts list until you find the TIdContext
that you are interested in, and then you can either send data directly to
its IOHandler, or you can cache the data in a queue within the TIdContext
and then have the OnExecute event send that queue when ready and safe to
do so.

--
Remy Lebeau (TeamB)
ehsan mohtadi

Posts: 10
Registered: 2/14/09
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 27, 2014 10:11 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
type
  TForm1 = class(TForm);
  ...
  private
    DevicePort: TIdPort;
    ClientPort: TIdPort;
  ...
  end;
 
procedure TForm1.FormCreate(AContext: TIdContext);
begin
  DevicePort := 10001;
  ClientPort := 10012;
 
  IdTCPServer1.Bindings.Clear;
  IdTCPServer1.Bindings.Add.Port := DevicePort;
  IdTCPServer1.Bindings.Add.Port := ClientPort;
  IdTCPServer1.Active := True;
end;
 
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Ctx: TIdContext;
  List: TList;
  I: Integer;
begin
  if AContext.Binding.Port = DevicePort then
  begin
    // read a message from the device as needed ...
    List := IdTCPServer1.Contexts.LockList;
    try
      for I := 0 to List.Count-1 do
      begin
        Ctx := TIdContext(List[I]);
        if (Ctx <> AContext) and (Ctx.Binding.Port = ClientPort) then
        begin
          // send message to Ctx as needed...
        end;
      end;
    finally
      IdTCPServer1.Contexts.UnlockList;
    end; 
  end else
  begin
    // read a message from a client as needed ...
    List := IdTCPServer1.Contexts.LockList;
    try
      for I := 0 to List.Count-1 do
      begin
        Ctx := TIdContext(List[I]);
        if (Ctx <> AContext) and (Ctx.Binding.Port = DevicePort) then
        begin
          // send message to Ctx as needed...
          Break;
        end;
      end;
    finally
      IdTCPServer1.Contexts.UnlockList;
    end; 
  end;
end;
 

Thanks Dear Remy
I have found this code in site .
Sending data have put in on execute . but i dont understand your mean about loop . and i don't how to use this example
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 28, 2014 1:47 PM   in response to: ehsan mohtadi in response to: ehsan mohtadi
ehsan wrote:

Sending data have put in on execute . but i dont understand your mean
about loop . and i don't how to use this example

The server is listening on 2 ports. If a client connected to the DevicePort
sends a message to the server, the message gets copied to every client that
is connected to the ClientPort, and vice versa. Seems pretty straight forward
to me. What exactly is not clear to you? Do you not know how to read/write
messages? What is the problem?

--
Remy Lebeau (TeamB)
ehsan mohtadi

Posts: 10
Registered: 2/14/09
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 29, 2014 11:48 PM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Dear Remy
some client are connected to my server and send data to it continuesly .but sometimes i want to send data from server to one of them .
Is it possible describe with one example . i confused .
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 30, 2014 11:44 AM   in response to: ehsan mohtadi in response to: ehsan mohtadi
ehsan wrote:

sometimes i want to send data from server to one of them .

I have posted examples of that many times before, on the Embarcadero forums,
Indy forums, StackOverflow, etc.

--
Remy Lebeau (TeamB)
ehsan mohtadi

Posts: 10
Registered: 2/14/09
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 31, 2014 5:35 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Dear Remy
is it possible get me its link address ?
ehsan mohtadi

Posts: 10
Registered: 2/14/09
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: May 31, 2014 9:55 PM   in response to: ehsan mohtadi in response to: ehsan mohtadi
Dear Remy
I has searched you on this site about idtcpserver.
But it is not related to my case !!!!!!!!!!!
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jun 1, 2014 2:12 AM   in response to: ehsan mohtadi in response to: ehsan mohtadi
ehsan wrote:

I has searched you on this site about idtcpserver.
But it is not related to my case !!!!!!!!!!!

I don't know what you are looking at, but I have discussed the issue of sending
unsolicited messages from server to clients on many occasions.

--
Remy Lebeau (TeamB)
Mark Buchert

Posts: 1
Registered: 11/7/13
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 3, 2014 10:11 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
I am extremely frustrated that I can NOT find a link to a simple demo - THAT WORKS (in XE4). I would like to see the 2 comp (TIdTCPClient, TIdTCPServer) connected and exchange simple text back and forth. It would be really nice to see such a project expanded to show it threaded in such a way to keep the main appl responsive.

Disappointed a demo project was not included with the XE4 project.

I have seen many ask for a link to a demo project that uses the Indy components (pref for XE4). Any project with the 2 components will do!

Remy Lebeau (TeamB) wrote:
ehsan wrote:

I has searched you on this site about idtcpserver.
But it is not related to my case !!!!!!!!!!!

I don't know what you are looking at, but I have discussed the issue of sending
unsolicited messages from server to clients on many occasions.

--
Remy Lebeau (TeamB)
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: TIdTCPServer for communication
Click to report abuse...   Click to reply to this thread Reply
  Posted: Jul 3, 2014 12:38 PM   in response to: Mark Buchert in response to: Mark Buchert
Mark wrote:

I am extremely frustrated that I can NOT find a link to a simple
demo - THAT WORKS (in XE4).

I have posted examples MANY times before on SEVERAL different forums (Embarcadero,
AToZed, StackOverflow).

I would like to see the 2 comp (TIdTCPClient, TIdTCPServer)
connected and exchange simple text back and forth.

Try something like the following:

Server:

type
  TClient = class(TIdContext)
  public
    UserName: String;
    Queue: TIdThreadSafeStringList;
  end;
 
constructor TClient.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; 
AList: TIdContextThreadList = nil);
begin
  inherited;
  Queue := TIdThreadSafeStringList.Create;
end;
 
destructor TClient.Destroy;
begin
  Queue.Free;
  inherited;
end;
 
procedure TForm1.FormCreate(Sender: TObject);
begin
  IdTCPServer1.ContextClass := TClient;
end;
 
procedure TForm1.IdTCPServer1Connect(AContext: TIdContext);
begin
  AContext.Connection.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
  TClient(AContext).UserName := AContext.Connection.IOHandler.ReadLn;
end;
 
procedure TForm1.IdTCPServer1Execute(AContext: TIdContext);
var
  Client: TClient;
  List, TempList: TStringList;
  S: String;
  I: Integer;
begin
  Client := TClient(AContext);
 
  TempList := nil;
  try
    List := Client.Queue.Lock;
    try
      if List.Count > 0 do
      begin
        TempList := TStringList.Create;
        TempList.Assign(List);
        List.Clear;
      end;
    finally
      Queue.Unlock;
    end;
    if TempList <> nil then
    begin
      for I := 0 to TempList.Count-1 do
      begin
        S := TempList[I];
        AContext.Connection.IOHandler.WriteLn(S);
        TThread.Queue(nil,
          procedure
          begin
            Memo1.Lines.Add('[to ' + Client.UserName + '] ' + S);
          end
        );
      end;
    end;
  finally
    TempList.Free;
  end;
 
  if AContext.Connection.IOHandler.InputBufferIsEmpty then
    AContext.Connection.IOHandler.CheckForDataOnSource(100);
 
  if not AContext.Connection.IOHandler.InputBufferIsEmpty then
  begin
    S := AContext.Connection.IOHandler.ReadLn;
    TThread.Queue(nil,
      procedure
      begin
        Form1.Memo1.Lines.Add('[from ' + Client.UserName + '] ' + S);
      end
    );
  end;
end;
 
procedure TForm1.SendMessageToClient(const AUserName, AMsg: String);
var
  List: TIdContextList;
  I: Integer;
  Client: TClient;
  AllClients: Boolean;
begin
  AllClients := (AUserName = '');
  List := IdTCPServer1.Contexts.LockList;
  try
    for I := 0 to List.Count-1 do
    begin
      Client := TClient(List[I]);
      if AllClients or TextIsSame(Client.UserName, AUserName) then
      begin
        Client.Queue.Add(AMsg);
        if not AllClients then
          Break;
      end;
    end;
  finally
    IdTCPServer1.Contexts.UnlockList;
  end;
end;
 
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
var
  User: String;
begin
  if Key = #13 then
  begin
    Key := #0;
    SendMessageToClient(UserName.Text, Edit1.Text);
    Edit1.Clear;
  end;
end;

Client:

type
  TClientThread = class(TThread)
  protected
    Conn: TIdTCPClient;
    procedure Execute; override;
  public
    Queue: TIdThreadSafeStringList;
    constructor Create; reintroduce;
    destructor Destroy; override;
    procedure SendMessageToServer(const AMsg: string);
  end;
 
constructor TClientThread.Create;
begin
  inherited Create(False);
  Conn := TIdTCPClient.Create;
  Conn.Host := ...;
  Conn.Port := ...;
  Conn.ConnectTimeout := 5000;
  ...
  Queue := TIdThreadSafeStringList.Create;
end;
 
destructor TClientThread.Destroy;
begin
  Conn.Free;
  Queue.Free;
  inherited;
end;
 
procedure TClientThread.Execute;
var
  Client: TClient;
  List, TempList: TStringList;
  S: String;
begin
  while not Terminated do
  begin
    try
      Conn.Connect;
    except
      TThread.Queue(nil,
        procedure
          Form1.Memo1.Lines.Add('Unable to connect!');
        end
      );
      I := 5;
      while (not Terminated) and (I > 0) do
      begin
        Sleep(1000);
        Dec(I);
      end;
      Continue;
    end;
 
    try
      try
        TThread.Queue(nil,
          procedure
            Form1.Memo1.Lines.Add('Connected!');
          end
        );
 
        Queue.Clear;
 
        Conn.IOHandler.DefStringEncoding := IndyTextEncoding_UTF8;
        Conn.IOHandler.WriteLn('UserName');
 
        while not Terminated do
        begin
          TempList := nil;
          try
            List := Queue.Lock;
            try
              if List.Count > 0 then
              begin
                TempList := TStringList.Create;
                TempList.Assign(List);
                List.Clear;
              end;
            finally
              Queue.Unlock;
            end;
            if TempList <> nil then
            begin
              for I := 0 to TempList.Count-1 do
              begin
                if Terminated then Break;
                Conn.IOHandler.WriteLn(TempList[I]);
                TThread.Queue(nil,
                  procedure
                    Form1.Memo1.Lines.Add('[to server] ' + TempList[I]);
                  end
                );
              end;
            end;
          finally
            TempList.Free;
          end;
 
          if Conn.IOHandler.InputBufferIsEmpty and (not Terminated) then
            Conn.IOHandler.CheckForDataOnSource(100);
 
          if (not Conn.IOHandler.InputBufferIsEmpty) and (not Terminated) 
then
          begin
            S := Conn.IOHandler.ReadLn;
            TThread.Queue(nil,
              procedure
              begin
                Form1.Memo1.Lines.Add('[from server] ' + S);
              end
            );
          end;
        end;
      finally
        Conn.Disconnect;
        TThread.Queue(nil,
          procedure
            Form1.Memo1.Lines.Add('Disconnected!');
          end
        );
      end;
    except
      TThread.Queue(nil,
        procedure
          Form1.Memo1.Lines.Add('Error!');
        end
      );
    end;
  end;
end;
 
procedure TClientThread.SendMessageToServer(const AMsg: string);
begin
  Queue.Add(AMsg);
end;
 
var
  Thread: TClientThread = nil;
 
procedure TForm1.ConnectButtonClick(Sender: TObject);
begin
  if Thread = nil then
    Thread := TClientThread.Create;
end;
 
procedure TForm1.DisconnectButtonClick(Sender: TObject);
begin
  if Thread <> nil then
  begin
    Thread.Terminate;
    Thread.WaitFor;
    FreeAndNil(Thread);
  end;
end;
 
procedure TForm1.Edit1KeyPress(AContext: TIdContext; var Key: Char);
var
  S: String;
begin
  if Key = #13 then
  begin
    Key := #0;
    if Thread <> nil then
      Thread.SendMessageToServer(Edit1.Text);
    Edit1.Clear;
  end;
end;


--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02