Solved

Writing an multi-threaded server/client for windows and linux using TTcpServer and TTcpClient

Posted on 2003-10-27
21
1,983 Views
Last Modified: 2012-05-04
Okay, this is my dilemma. I have a working client/server currently using the components TServerSocket / TClientSocket in a multithreaded server/client environment.

I just cant figure out how the TTcpServer and TTcpClient works.

The TTcpServer need to be multithreaded and I would very much like if someone could give me a working basic example.

Preferrably the code should not use any visual TTcpServer/TTcpClient  componets.


If you can help me understand how the component works and give me a nice example, then perhaps you'll get some more points.


Thanks in advance!
0
Comment
Question by:svenneman
  • 9
  • 5
  • 5
  • +2
21 Comments
 
LVL 6

Expert Comment

by:swift99
ID: 9631387
Switch to ICS.  It's free, it's more reliable, and you have all the (delphi) source code available.  see http://overbyte.delphicenter.com

This was the first piece of advice anyone ever gave me on EE, and it is the one piece that I pass on most frequently
0
 

Author Comment

by:svenneman
ID: 9631967
ICS doesnt use the same codebase and units for both kylix and delphi does it?

Kylix/Delphi both uses the Sockets unit and it includes working TTcpServer and TTcpClient components
0
 
LVL 17

Expert Comment

by:geobul
ID: 9632348
Hi,

Look at this question:
http://www.experts-exchange.com/Programming/Programming_Languages/Delphi/Q_20778629.html

Perhaps this is what you're looking for.

Regards, Geo
0
 

Author Comment

by:svenneman
ID: 9632884
Not really... I need a server which uses a new thread for every single connection. A thread which I can see and edit myself. Just like with multithreaded servers with TServerSocket.

TServerSocket does not exist in Kylix or in delphi 7.
0
 
LVL 17

Expert Comment

by:geobul
ID: 9633352
TTcpServer is multi-threaded by itself. It allocates and launches a separate thread (TIdPeerThread by default) for every client connection internally. You don't need to do that yourself ! You can access a client thread initially in OnConnect event (AThread parameter). Read 'Threads' property to obtain the list of currently active client connections threads. You may access the threads by there. Indy makes your life easier (creates and maintains the necessary things internally) but you still have an access to them.

Regards, Geo
0
 
LVL 17

Expert Comment

by:geobul
ID: 9633755
Perhaps you might create your own thread class (descending from TIdPeerThread) and use that class:

  TMyClientThread = class(TIdPeerThread)
    //
  end;
...
procedure TForm1.Button1Click(Sender: TObject);
begin
  IdTCPServer1.ThreadClass := TMyClientThread;
  IdTCPServer1.Active := true;
end;

Regards, Geo
0
 

Author Comment

by:svenneman
ID: 9634929
"TTcpServer is multi-threaded by itself. It allocates and launches a separate thread (TIdPeerThread by default) for every client connection internally."

No thats TIdTcpServer... TTcpServer is the default one coming with delphi that doesnt use Indy components at all.


Interresting about your last post... I'll try that, if that works as expected you will be given points for it... but I'd rather use the TTcpServer component if possible.

Lets say I define my own thread class as you described... how do I read/write data to the connection with it?

In my own server module (TServerSocket) I used something like this in the thread:
TMyThreadclass.ClientExecute();
begin
while not (Terminated) AND (ClientSocket.Connected) do
begin
   try
      SocketStream := TPodWinSocketStream.Create(ClientSocket, connectionSettings.timeout);
      //Do stuff here, check if data is available etc and write to socket.
   finally
      SocketStream.Free;
   end;
end;
end;


How do I incorporate something like that in Indy? Or would one do it some other way?
The communication thread should not only sit and listen... it should do tasks every "cycle" like writing to socket... check if some variables have changed etc.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9635050
I typically keep communications in a thread entirely separate from business logic - it improves scalability.

In WIndows, I either post the command request string to a queue, or create and populate a command object and post that to a queue.  I run one thread per CPU that pops command/command requests from the queue and processes them.  On completion, I post a result back to a response queue and post an event that says that there are responses waiting to be transmitted.  The communication sthread then pops the response and returns it to the caller.

In a linux system it is often more efficient to keep business and communications logic in the same thread, and to run one thread per connection.

The difference in the TCP handling models demands very different ways of dealing with the question of threading and sockets.

0
 
LVL 17

Expert Comment

by:geobul
ID: 9635468
I'm so sorry. I was talking about TIdTcpServer all the time. Sorry once again.
0
 

Author Comment

by:svenneman
ID: 9635559
If you could give me some more hints on how to work with (custom)threads with indy I'd be greatful.

I might be able to use indy instead if it works okay.
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 

Author Comment

by:svenneman
ID: 9643961
Indy doesnt work in the way I would like to use the socket... Indy is event driven... which I dont want.

TServerSocket when written as a multithreaded server works in the following way... I assume the TTcpServer works in a similar way due to the similar structure of the two components. However it doesnt use a TWinSocketStream to send data. I've searched everywhere on the web for examples of TTcpServer, noone seems to be using it, or at least noone writes about it.

If anyone have a working example of a multi-threaded server built with TTcpServer then I'd be greatful if I could have a peek at it.

What I want to do is to preform stuff in the threads Execute method.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9644222
You are trying to use a blocking model of operation, which would cause the TCP mechanism in Windows to fail.  If you block the thread, then no data can be received from TCP.

In the Windows world, it is better to keep all communications in one thread, and perform the business logic in another thread.  Use events to post messages across the threads.  Use a command pattern to minimize network traffic and issues with session level control.  In your model, the "command" object is a thread.
0
 

Author Comment

by:svenneman
ID: 9644730
so what you're saying is that a threadblocking TTcpServer simply wont work?

umm no... I cant agree on that.
0
 
LVL 6

Expert Comment

by:swift99
ID: 9644797
In windows, communication from TCP to your process is all through the Windows event queue.  A truly blocking mechanism cannot work in a Windows environment because the act of blocking the thread isolates the thread from TCP for the duration of the block.  You can write your own TCP replacement that supports a blocking model.  PVM does this for use in Beowulf systems.

The TCP to process communication model is different in linux systems, so a blocking TCP component is not only sensible but preferable in that environment.

Serious server programming really cannot be anything but OS dependent.
0
 

Author Comment

by:svenneman
ID: 9645303
is a threadblocking server unusable in windows or does it just offer less performance than written through events?

because I have a working TServerSocket server written in threadblocking mode and it works just great.

Wouldnt it be possible to write something similar with the TTcpServer? That is what my question was from the beginning. Because then I can use it in both windows and unix, as the control is os independent (TServerSocket is not).


The reason I need this is because the server performs database queries and alot of calculations, (some takes time), and I those things must not block the rest of the application, and the socket should wait for these operations to finish.


In my current server I keep the socket in a thread along with all other functions/procedures that should be used on request from the client to the server.


I dont see how I could write something similar without doing it that way. (one thread for each client connected which performs all tasks independent of each other).

As I've pointed out before use the TServerSocket in my old server in the following way:

When a client connets a new thread is spawned which looks like this.

TMyThreadclass.ClientExecute();
begin
while not (Terminated) AND (ClientSocket.Connected) do
begin
   try
      SocketStream := TWinSocketStream.Create(ClientSocket, connectionSettings.timeout);
      //Do stuff here, check if data is available etc and write to socket.
   finally
      SocketStream.Free;
   end;
end;
end;

Is it possible to do about the same thing with the TTcpServer component?
0
 
LVL 6

Expert Comment

by:swift99
ID: 9646096
It is unusable because Windows message pump/event loop is the mechanism by which TCP packets are transferred to your application.  No loop, no network I/O.

I would lay odds that you have a pseudo blocking tool.  The component has its own event loop and perofrms a number of operations to appear to be blocking.  This model is prone to data loss at high levels of saturation.
0
 
LVL 1

Accepted Solution

by:
velter earned 500 total points
ID: 9646559
Use Indy TIdTcpServer, I think it works like you want. If you do not use any visual component, you can use this code :

TServer = class(TIdTCPServer)
private
   procedure DoExecute(eThread: TIdPeerThread);
public
   constructor Create(ePort : Word);
end;

...

constructor TServer.Create(ePort : Word);
begin
   inherited Create(nil);
   OnExecute:=DoExecute;

   // Fix the port on which the server is listening
   DefaultPort:=ePort;

  // Activate the server
   Active:=true;
end;

procedure TServer.DoExecute(eThread: TIdPeerThread);
begin
   // Do your stuff here. This event is called in a new thread for each incomming connection.
   // Basicaly, you read, do some stuff write...

   // Close the connection
   eThread.Terminate;
end;
0
 
LVL 17

Expert Comment

by:geobul
ID: 9648548
BTW I friend of mine once told me that TServerSocket does exist in Delphi7 but you have to add a unit in uses clause (can't remember which one) and create that component in run-time. I personally have no D7 (yet) in order to confirm that. Have anybody heard something like that?
0
 
LVL 1

Expert Comment

by:winexec
ID: 9648738
Yes, TServerSocket and TClientSocked exist in Delphi 7 and must be installed manually, as it says in a ReadMe.txe from Delphi directory.
0
 

Author Comment

by:svenneman
ID: 9649002
Thanks velter... that seems to be working just great!
0
 

Author Comment

by:svenneman
ID: 9649286
And thanks to everyone else who at least tried to help
0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
In my programming career I have only very rarely run into situations where operator overloading would be of any use in my work.  Normally those situations involved math with either overly large numbers (hundreds of thousands of digits or accuracy re…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now