Board index » cppbuilder » Reading data from TServerSocket in TClientSocket

Reading data from TServerSocket in TClientSocket


2006-01-01 09:18:53 AM
cppbuilder31
Hello,
Thanks to Remy, I was able to send data(text/file) to a TSocket server
program. This is true for both text and files sent to the server. (1)
However, when trying to read data from TScoket to the ClientSocket, it does
not work. Here is the code I put in the ClientSocket->OnRead event:
void __fastcall TForm1::ClientSocket1Read(TObject *Sender,
TCustomWinSocket *Socket)
{
const int BytesToReceive = Socket->ReceiveLength();
if( BytesToReceive <= 0 )
return;
Memo1->Lines->Add("Server Transmitting: ");
TMemoryStream *ServerData = new TMemoryStream;
char *Buffer[256];
Socket->ReceiveBuf(Buffer, BytesToReceive);
ServerData->Write(Buffer, BytesToReceive);
ReadPacket(ServerpStream); <- ReadPacket takes a TStream object
}
Here is the relevant code from the server end:
void __fastcall TMyServerThread::ClientExecute(void)
{
.................
while (!Terminated && ClientSocket->Connected)
{
if (pStream->WaitForData(6000))
{
ReadPacket(pStream);
TMemoryStream *Strm2 = new TMemoryStream;
Strm2->Clear();
FileName = "Thank You";
BinaryTransfer1->SendTextMessage(Strm2, FileName);
ClientSocket->SendBuf(Strm2->Memory, Strm2->Size);
}
}
}
(2) Is ClientSocket->OnRead executed in a seperate thread? (3) If not, is
it wise to execute a client read in a seperate thread? (4) And if so, how
do I accomplish that?
These Misc Read/Write functions are defined in both the server and the
client. I use the same functions for consistencies sake:
//--------------------------------------------------------------------------
-
bool __fastcall TForm1::ReadPacket(TStream *Stream)
{
char type = 0x00;
AnsiString FileName;
if( ReadBuf(Stream, &type, sizeof(char)) )
{ //ShowMessage(" type " + String(type));
switch( type )
{
case 0x01: // text
{
AnsiString Msg;
if( ReadString(Stream, Msg) )
{
// use msg as needed ...
ShowMessage(Msg);
return true;
}
break;
}
case 0x02: // file
{
if( ReadFile(Stream, FileName) )
{
// use FileName as needed...
return true;
}
break;
}
default: // unknown type
{
// unknown data received, do something...
break;
}
}
}
return false;
}
bool __fastcall TForm1::ReadBuf(TStream *Stream, void *Buffer, int BufSize)
{
BYTE *pBuf = (BYTE*) Buffer;
int NumRead;
try
{
while( BufSize>0 )
{
NumRead = Stream->Read(pBuf, BufSize);
if( NumRead < 1 )
return false;
pBuf += NumRead;
BufSize -= NumRead;
}
}
catch(const Exception &)
{
return false;
}
return true;
}
bool __fastcall TForm1::ReadString(TStream *Stream, AnsiString &S)
{
bool status = false;
int length = 0;
if( ReadBuf(Stream, &length, sizeof(int)) )
{
if( length>0 )
{
try
{
S.SetLength(length);
}
catch(const Exception &)
{
return false;
}
status = ReadBuf(Stream, S.c_str(), length);
return status;
}
else
{
S = "";
return true;
}
}
return false;
}
bool __fastcall TForm1::ReadFile(TStream *Stream, AnsiString &FileName)
{
AnsiString fn = FileName, fn2;
if( ReadString(Stream, fn) )
{
fn2 = ExtractFileName(fn);
fn = ("C:\\temp\\" + fn2);
int size = 0;
if( ReadBuf(Stream, &size, sizeof(int)) )
{
bool error = false;
try
{
TFileStream *FS = new TFileStream(fn, fmCreate);
try
{
//FS->Size = size;
BYTE rbuf[256];
int bufsize;
bufsize = size;
while( size>0 )
{
// bufsize = size;
if( bufsize>sizeof(rbuf) )
bufsize = sizeof(rbuf);
if( !ReadBuf(Stream, rbuf, bufsize) )
{
error = true;
break;
}
if( FS->Write(rbuf, bufsize) < 1 )
{
error = true;
break;
}
size -= bufsize;
}
}
__finally
{
delete FS;
}
}
catch(const Exception &)
{
error = true;
DeleteFile(fn);
}
if( !error )
{
FileName = fn;
return true;
}
}
}
return false;
}
 
 

Re:Reading data from TServerSocket in TClientSocket

Correction:>Here is the relevant code from the server end:
void __fastcall TMyServerThread::ClientExecute(void)
{
.................
while (!Terminated && ClientSocket->Connected)
{
if (pStream->WaitForData(6000))
{
ReadPacket(pStream);
TMemoryStream *Strm2 = new TMemoryStream;
Strm2->Clear();
FileName = "Thank You";
SendTextMessage(Strm2, FileName);
ClientSocket->SendBuf(Strm2->Memory, Strm2->Size);
}
}
}
Quote
Here is the relevant code from the server end:
 

Re:Reading data from TServerSocket in TClientSocket

Maurice Anderson wrote:
Quote
However, when trying to read data from TScoket to the ClientSocket, it does
not work. Here is the code I put in the ClientSocket->OnRead event:

void __fastcall TForm1::ClientSocket1Read(TObject *Sender,
TCustomWinSocket *Socket)
{

const int BytesToReceive = Socket->ReceiveLength();
if( BytesToReceive <= 0 )
return;

Memo1->Lines->Add("Server Transmitting: ");
That's on the main form?
I think you are supposed to Synchronize() with the main thread first.
Quote
TMemoryStream *ServerData = new TMemoryStream;
char *Buffer[256];
First, should be
char Buffer[256];
Second, 256 is probably too small.
Should be larger than BytesToReceive.
char * Buffer = new char[BytesToReceive];
Quote
Socket->ReceiveBuf(Buffer, BytesToReceive);
delete[] Buffer;
Quote
(2) Is ClientSocket->OnRead executed in a seperate thread?
Yes, usually.
Quote
(3) If not, is it wise to execute a client read in a seperate thread?
Yes.
Quote
(4) And if so, how do I accomplish that?
Use the OnRead event.
 

{smallsort}

Re:Reading data from TServerSocket in TClientSocket

Quote
I think you are supposed to Synchronize() with the main thread first.
Hello Bob, I updated my code with your suggestions but to no avail..... as
in:
while (!Terminated && ClientSocket->Connected)
{
if (pStream->WaitForData(6000))
{
ReadPacket(pStream);
Synchronize(DoStuffOnMainForm);
}
}
void __fastcall TMyServerThread::DoStuffOnMainForm(void)
{
AnsiString FileName = "Hello World";
Strm2 = new TMemoryStream;
Strm2->Clear();
BinaryTransfer1->SendTextMessage(Strm2, FileName);
ClientSocket->SendBuf(Strm2->Memory, Strm2->Size);
}
Quote
Should be larger than BytesToReceive.
char * Buffer = new char[BytesToReceive];
I also replaced char *Buffer[256] with char * Buffer = new
char[BytesToReceive];
Quote
>(2) Is ClientSocket->OnRead executed in a seperate thread?

Yes, usually.
Are you saying that there are times that ClientSocket->OnRead will execute
in the main thread? If so what would cause it to alternate between
executing in a seperate thread and executing in the main thread?
Quote
>(4) And if so, how do I accomplish that?

Use the OnRead event.
That's the event my code is executing in
 

Re:Reading data from TServerSocket in TClientSocket

Maurice Anderson wrote:
Quote
while (!Terminated && ClientSocket->Connected)
{
if (pStream->WaitForData(6000))
{
ReadPacket(pStream);
Synchronize(DoStuffOnMainForm);
I don't know why you would want to do that with DoStuffOnMainForm
since it doesn't seem to do stuff with the main form?
Quote
void __fastcall TMyServerThread::DoStuffOnMainForm(void)
{
AnsiString FileName = "Hello World";
Strm2 = new TMemoryStream;
Strm2->Clear();
BinaryTransfer1->SendTextMessage(Strm2, FileName);
ClientSocket->SendBuf(Strm2->Memory, Strm2->Size);
}
>>(2) Is ClientSocket->OnRead executed in a seperate thread?
>
>Yes, usually.

Are you saying that there are times that ClientSocket->OnRead will execute
in the main thread? If so what would cause it to alternate between
executing in a seperate thread and executing in the main thread?
It is just a function, after all. Anyone can call it. Usually you
don't call it, and let it operate as intended.
 

Re:Reading data from TServerSocket in TClientSocket

"Maurice Anderson" < XXXX@XXXXX.COM >wrote in message
Quote
However, when trying to read data from TScoket to
the ClientSocket, it does not work.
Just saying that it does not work says nothing at all about the actual
problem you are having. Always provide specific details.
Quote
Here is the code I put in the ClientSocket->OnRead event:
I assume, then, that you are using the TClientSocket in non-blocking mode?
The code I gave you earlier was designed to be used in blocking mode, since
you said that you were using TWinSocketStream. The code has to be modified
a bit to be usable with a non-blocking socket due to the more frequent
occurances of incomplete data arriving in the socket at any given time. The
code you have so far is not enough to handle incoming packets in a reliable
manner. You must buffer all incoming data and then process it only when
enough data is actually available. You can go to www.deja.com and
search the newsgroup archives. Sample code has been posted many many times
before.
Quote
Here is the relevant code from the server end:
You are not doing any error cheecking in that code. And I do not see you
filling the TMemoryStream with any data before sending it.
Quote
Is ClientSocket->OnRead executed in a seperate thread?
The OnRead event is triggered in the same thread that owns the
TClientSocket. TClientSocket is not a threaded component lik TServerSocket
can be. If you want to use TClientSocket with threads, then you have to
manage the threading yourself.
Quote
If not, is it wise to execute a client read in a seperate thread?
That will only work if you use the TClientSocket in blocking mode.
TClientSocket is not thread-safe in non-blocking mode.
Quote
These Misc Read/Write functions are defined in both the server and the
client. I use the same functions for consistencies sake:
The functions will work as long as the data is accurate, which is not always
the case with the code you have shown so far.
Also, I will mention that your use of ShowMessage() is not thread-safe. You
cannot safely use ShowMessage() outside of the main thread. If you want to
display a message in a thread-safe manner, then use the Win32 API
MessageBox() function.
Gambit
 

Re:Reading data from TServerSocket in TClientSocket

"Bob Gonder" < XXXX@XXXXX.COM >wrote in message
Quote
>Memo1->Lines->Add("Server Transmitting: ");

That's on the main form?
I think you are supposed to Synchronize() with the main thread first.
According to the code, the access to the Memo is in an event that is
triggered in the main thread to begin with.
Gambit
 

Re:Reading data from TServerSocket in TClientSocket

"Maurice Anderson" < XXXX@XXXXX.COM >wrote in message
Quote
Hello Bob, I updated my code with your suggestions but to no avail
Those changes were unnecessary.
Quote
Are you saying that there are times that ClientSocket->OnRead
will execute in the main thread?
If you are using TClientSocket in the main thread to begin with, then the
OnRead event will always be triggered in the context of the main thread.
TClientSocket is not a threaded component.
Quote
If so what would cause it to alternate between executing in a
seperate thread and executing in the main thread?
It wouldn't ever do that.
Gambit