 |
BorlandTalk.com Borland discussion newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Johnny Hansen Guest
|
Posted: Mon Dec 29, 2003 9:12 am Post subject: Writing to an ServerClientThread ? |
|
|
Hi,
I have made a program that act as server and every time a client connects,
the server creates a new thread for the communication.
The client can send to the server and by means of a postmessage can I send
the data received from the client to the servers main-thread, and this works
just fine. My question is now, how do I send/write to the client.
I have create a TwinSocketStream for holding the data received in the thread
and as fare I understand is the right way of writing to the client by using
the TwinSocketStream write metode, but have do I get my data to the right
thread if more than one thread has been created (more than one client
connected).
Hope for some help.
Best regards
Johnny
|
|
| Back to top |
|
 |
Martin James Guest
|
Posted: Mon Dec 29, 2003 9:22 am Post subject: Re: Writing to an ServerClientThread ? |
|
|
| Quote: | I have create a TwinSocketStream for holding the data received in the
thread
and as fare I understand is the right way of writing to the client by
using
the TwinSocketStream write metode, but have do I get my data to the right
thread if more than one thread has been created (more than one client
connected).
|
You could pass the TwinSocketStream in the message, either directly or as a
field of some 'communication object' that contains the incoming data from
the client & write methods that hide the TwinSocketStream from the main
thread. You could pass the whole ServerClientThread in the message, but you
probably don't want all the thread gunge accessible from your main form.
Writing directly from the main thread like this is fine as long as the
serverClientThread is only reading. If the ServerClientThread also writes,
(eg. echoing input chars), the write method will need a CS to prevent the
main thread and SC thread writing at the same time.
Rgds,
Martin
|
|
| Back to top |
|
 |
Johnny Hansen Guest
|
Posted: Mon Dec 29, 2003 9:50 am Post subject: Re: Writing to an ServerClientThread ? |
|
|
Hi
I have this idea that I can make a procedure in the thread link this one
procedure SendData(var DataTilClient: string);
begin
TxData := DataTilClient;
end;
Where TxData is of type string define in the thread, from my main-thread I
can call this procedure with the "message" I want to as a parameter.
In the ClientExecute must I then have the following code
while (not Terminated) and ClientSocket.Connected do
begin
if SockStream.WaitForData(FClientTimeOut) then
begin
try
SetLength(RequestBuf,BlockSize);
try
LenReceived := SockStream.Read(RequestBuf[1], Length(RequestBuf));
except
break;
end;
if length(TxData) > 0 then
SockStream.Write(TxData[1],length(TxData)); // write data to the
client
if (LenReceived > 0) then
begin
inc(ReqPerSec);
SetLength(RequestBuf, LenReceived );
postmessage(main.Handle,WM_USER + 1,WM_USER +
2,integer(PChar(RequestBuf)));
end
else
BREAK; // client has send zero data
except
BREAK; // stream read error, unexpected disconnect, ...
end;
end
else
BREAK; // client did not send data within timeout limit
end;
But if I use this way, I must be sure that all thread has send the data to
the clients before I change the TxData and that's why I must be sure of
which thread has been called.
Is this a dead approach ?.
"Martin James" <mjames_falcon (AT) dial (DOT) pipex.com> skrev i en meddelelse
news:3feff236 (AT) newsgroups (DOT) borland.com...
| Quote: |
I have create a TwinSocketStream for holding the data received in the
thread
and as fare I understand is the right way of writing to the client by
using
the TwinSocketStream write metode, but have do I get my data to the
right
thread if more than one thread has been created (more than one client
connected).
You could pass the TwinSocketStream in the message, either directly or as
a
field of some 'communication object' that contains the incoming data from
the client & write methods that hide the TwinSocketStream from the main
thread. You could pass the whole ServerClientThread in the message, but
you
probably don't want all the thread gunge accessible from your main form.
Writing directly from the main thread like this is fine as long as the
serverClientThread is only reading. If the ServerClientThread also
writes,
(eg. echoing input chars), the write method will need a CS to prevent the
main thread and SC thread writing at the same time.
Rgds,
Martin
|
|
|
| Back to top |
|
 |
Martin James Guest
|
Posted: Mon Dec 29, 2003 11:19 am Post subject: Re: Writing to an ServerClientThread ? |
|
|
"Johnny Hansen" <johnny (AT) jokiha (DOT) dk> wrote
| Quote: | Hi
I have this idea that I can make a procedure in the thread link this one
|
<snip poor polling code>
| Quote: |
Is this a dead approach ?.
|
Well, it's not dead but it has a poor quality of life. Any polling approach
is just a bad idea if it can be avoided. Not only is it a waste of CPU, but
there is inevitable latency - waiting for the rx timeout before sending is
just not necessary.
Post off your data and send method to the main thread - it's so much easier.
You could use an object like:
TcommsObject=class(Tobject)
private
inputBuffer:array[0.255] of char;
ioStream:TwinSocketStream;
public
procedure send(outStr:string);
end;
Create one at the top of your 'clientExecute' loop, load data into the
buffer as it is received until your EOL char, (or whatever your protocol
uses to define 'end of message'), load up the ioStream field with your
thread TwinSocketStream and then post it off to the main thread:
postMessage(MainThreadHandle,WM_INDATA,integer(thisCommsObject),0);
The thread can then immediately create another commsObject & start receiving
stuff while the previous one is on its way to the main thread or being
processed there. There is no need for anything to wait or poll under
'normal' loadings.
The send method need do no more than write to the private socket stream. Of
course, you could add more methods to the comms object - if you have a
special protocol to check, you could have a 'doProtocol(inChar:char)' method
that does all that stuff on a character-by-character basis & loads up fields
in the commsObject with commands, data etc. extracted from the input stream.
When the main thread is finished with a comms object, it can simply free it.
If the data being transferred is large and/or bursty, there are more complex
schemes where a pool of comms objects can be shared by all the serverClient
threads, so eliminating the overhead of memory-management calls, but this is
not really essential unless you really need high performance.
Rgds,
Martin
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Mon Dec 29, 2003 6:10 pm Post subject: Re: Writing to an ServerClientThread ? |
|
|
"Martin James" <mjames_falcon (AT) dial (DOT) pipex.com> wrote
| Quote: | Writing directly from the main thread like this is fine as long as the
serverClientThread is only reading. If the ServerClientThread also
writes, (eg. echoing input chars), the write method will need a CS
to prevent the main thread and SC thread writing at the same time.
|
TWinSocketStream already does that internally, by calling the Socket's
Lock() and Unlock() methods when you call Read() and Write().
Gambit
|
|
| Back to top |
|
 |
Martin James Guest
|
Posted: Mon Dec 29, 2003 6:14 pm Post subject: Re: Writing to an ServerClientThread ? |
|
|
| Quote: |
TWinSocketStream already does that internally, by calling the Socket's
Lock() and Unlock() methods when you call Read() and Write().
|
OK I never had the source for these units & so always put in a CS.when 2+
threads were writing. Obviously a redundant op!
Rgds,
Martin
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Mon Dec 29, 2003 6:23 pm Post subject: Re: Writing to an ServerClientThread ? |
|
|
"Johnny Hansen" <johnny (AT) jokiha (DOT) dk> wrote
| Quote: | The client can send to the server and by means of a postmessage can
I send the data received from the client to the servers main-thread, and
this works just fine. My question is now, how do I send/write to the
client. |
One way would be to simply pass the thread's TWinSocketStream in the message
itself, ie:
void __fastcall TMyThread::ClientExecute()
{
TWinSocketStream *Strm = new TWinSocketStream(ClientSocket, 5000);
//...
PostMessage(Application->MainForm->Handle, WM_SOMEMSG, 0,
reinterpret_cast<LPARAM>(Strm));
//...
delete Strm;
}
void __fastcall TForm1::WndProc(TMessage &Message)
{
if( Message.Msg == case WM_SOMEMSG )
{
//...
TWinSocketStream *Strm =
reinterpret_cast<TWinSocketStream*>(Message.LParam);
try
{
Strm->Write(YourData, YourDataize);
}
catch(const Exception&)
{
}
}
}
Alternatively, you can pass the ClientSocket pointer in the message itself,
and Then when the main thread needs to send data, it can pass that pointer
to the TServerSocket's GetClientThread() method to ensure that the socket is
still valid at the time, and if so then write to it with another
TWinSocketStream. For example:
void __fastcall TMyThread::ClientExecute()
{
//...
PostMessage(Application->MainForm->Handle, WM_SOMEMSG, 0,
reinterpret_cast<LPARAM>(ClientSocket));
//...
}
void __fastcall TForm1::WndProc(TMessage &Message)
{
if( Message.Msg == case WM_SOMEMSG )
{
//...
TServerClientWinSocket *Socket =
reinterpret_cast<TServerClientWinSocket*>(Message.LParam);
TServerClientThread *Thread =
ServerSocket1->Socket->GetClientThread(Socket);
if( Thread )
{
try
{
TWinSocketStream *Strm = new
TWinSocketStream(Thread->ClientSocket, 5000);
try {
Strm->Write(YourData, YourDataize);
}
__finally {
delete Strm;
}
}
catch(const Exception&)
{
}
}
}
}
Alternatively, you could expose a public Write() method in your thread class
that accesses the thread's own TWinSocketStream internally, and then simply
call that method when needed, ie:
class TMyThread : public TServerClientThread
{
private:
TWinSocketStream *Strm;
//...
public:
//...
int __fastcall WriteData(void *Buffer, int BufSize);
};
void __fastcall TMyThread::ClientExecute()
{
Strm = new TWinSocketStream(ClientSocket, 5000);
//...
PostMessage(Application->MainForm->Handle, WM_SOMEMSG, 0,
reinterpret_cast<LPARAM>(ClientSocket));
//...
delete Strm;
Strm = NULL;
}
int __fastcall TMyThread::WriteData(void *Buffer, int BufSize)
{
if( Strm )
return Strm->Write(Buffer, BufSize);
return -1;
}
void __fastcall TForm1::WndProc(TMessage &Message)
{
if( Message.Msg == case WM_SOMEMSG )
{
//...
TServerClientWinSocket *Socket =
reinterpret_cast<TServerClientWinSocket*>(Message.LParam);
TMyThread *Thread =
static_cast<TMyThread*>(ServerSocket1->Socket->GetClientThread(Socket));
if( Thread )
{
try {
Thread->WriteData(YourData, YourDataize);
}
catch(const Exception&)
{
}
}
}
}
Gambit
|
|
| Back to top |
|
 |
Remy Lebeau (TeamB) Guest
|
Posted: Mon Dec 29, 2003 6:24 pm Post subject: Re: Writing to an ServerClientThread ? |
|
|
"Martin James" <mjames_falcon (AT) dial (DOT) pipex.com> wrote
| Quote: | OK I never had the source for these units & so always put in a
CS.when 2+ threads were writing. Obviously a redundant op!
|
TCustomWinSocket has its own internal CS.
Gambit
|
|
| Back to top |
|
 |
Markku Uttula Guest
|
Posted: Mon Dec 29, 2003 9:39 pm Post subject: Re: Writing to an ServerClientThread ? |
|
|
Martin James wrote:
| Quote: | TWinSocketStream already does that internally, by calling the
Socket's Lock() and Unlock() methods when you call Read() and
Write().
OK I never had the source for these units & so always put in a
CS.when 2+ threads were writing. Obviously a redundant op!
|
Hmm. I could be totally wrong (I usually am), but that sounds not only
unneeded (as was stated that TWinSocketStream already has a
criticalsection) but also a possible lockup-point. Was there not
something seriously wicked about introducing two criticalsections at
the same time for the same job or have I just dreamt this once again
and it has nothing in it after all?
--
Markku Uttula
|
|
| Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|