I have a rather curious problem. I have a multithreaded client server app built using Lazarus 1.4 and Indy 10 that I'm working on. It uses threads to send & receive data streams from the server. Each module creates its own self-terminating worker thread for this purpose. However I also need to create a special message worker thread that receives messages from the server like when a database backup is in progress. This message thread is created by the application mainform & remains active as long as the client application is active.
The server handles the sending of the data - message or database data - without problems. The issue is how to ensure that on the client side, server messages are read only by the message thread. All threads have Execute() procedures to process server communications.
My questions
Will using a Thread ID for the message thread allow me to directly target the message thread when the server is passing a message.
Alternatively, will limiting the messages to a certain size help in filtering messages meant for the client message thread (this is what I use actually but sometimes it fails).
Might I add that that all the client side threads use a common IdTCPClient to read server communications. I use critical sections to protect it.
The code for the message thread is shown below:
procedure TMsgThread.Execute;
var
LBuffer: TBytes;
LMessage: TBytes;
LDataSize: Integer;
LMsgProtocol: TMsgProtocol;
begin
//inherited; // Gives abstract methods cannot be called directly
// while the thread is not terminated and the client is connected
while NOT Terminated and FTCPClient.Connected do
begin
Lock;
//
try
if not FTCPClient.IOHandler.InputBufferIsEmpty and
(FTCPClient.IOHandler.InputBuffer.Size >= szMsgProtocol) and
(FTCPClient.IOHandler.InputBuffer.Size < szProtocol) then
begin
InitMsgProtocol(LMsgProtocol);
// store the size of the InputBuffer in LDataSize
LDataSize := FTCPClient.IOHandler.InputBuffer.Size;
if LDataSize >= szMsgProtocol then
try
// then read from InputBuffer the size of the protocol structure
FTCPClient.IOHandler.ReadBytes(LBuffer, szMsgProtocol);
// convert array of bytes to protocol
LMsgProtocol := BytesToMsgProtocol(LBuffer);
// check the command
case LMsgProtocol.Command of
cmdBackupDatabase:
begin
//
end; // cmdBackup: begin
cmdPulse:
begin
// Read the message sent by the server
FMessage := LMsgProtocol.Message;
// set the command to cmdKeepAlive
LMsgProtocol.Command := cmdKeepAlive;
// Convertir le protocol en bytes
LBuffer := MsgProtocolToBytes(LMsgProtocol);
// Envoyez la requĂȘte en bytes au serveur
FTCPClient.IOHandler.Write(LBuffer);
//
Synchronize(@Self.DoConnectionAlive);
end;
end; // case LProtocol.Command of
finally
// clear buffer and message
ClearBuffer(LBuffer);
ClearBuffer(LMessage);
end; // tryf
Sleep(100);
end;
finally
Unlock;
end;
end; // while NOT Terminated and FTCPClient.Connected do begin
end;
The Execute methods for the other self-terminating threads are similar in structure to that shown above. I got it from a model on the Internet. szMsgProtocol is the size of the message protocol while szProtocol is the size of the data protocol. So essentially, in the Execute() above I am concerned with InputBuffer contents that have a size equal to or larger than the message protocol but strictly less than the data protocol. This is how I planned to sift the streams sent by the server.