🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
8 messages
8 total messages Started by Maurice Anderson Sun, 01 Jan 2006 01:18
Reading data from TServerSocket in TClientSocket
#2970
Author: Maurice Anderson
Date: Sun, 01 Jan 2006 01:18
211 lines
6980 bytes
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
#2971
Author: Maurice Anderson
Date: Sun, 01 Jan 2006 01:23
21 lines
1513 bytes
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);
        }
}
}


>  Here is the relevant code from the server end:
Re: Reading data from TServerSocket in TClientSocket
#2972
Author: Bob Gonder
Date: Sun, 01 Jan 2006 03:45
44 lines
2204 bytes
Maurice Anderson wrote:

>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.

>  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];

>  Socket->ReceiveBuf(Buffer, BytesToReceive);

	delete[] Buffer;

>(2) Is ClientSocket->OnRead executed in a seperate thread?

Yes, usually.

>  (3) If not, is it wise to execute a client read in a seperate thread?

Yes.

>  (4) And if so, how do I accomplish that?

Use the OnRead event.
Re: Reading data from TServerSocket in TClientSocket
#2973
Author: Maurice Anderson
Date: Sun, 01 Jan 2006 04:06
44 lines
2217 bytes
>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);
}

> Should be larger than BytesToReceive.
> char * Buffer = new char[BytesToReceive];

I also replaced char *Buffer[256] with char * Buffer = new
char[BytesToReceive];

> >(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?

> >  (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
#2974
Author: Bob Gonder
Date: Sun, 01 Jan 2006 07:22
32 lines
2200 bytes
Maurice Anderson wrote:

>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?

>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
#2877
Author: Remy Lebeau (TeamB)
Date: Mon, 02 Jan 2006 22:49
53 lines
3306 bytes
"Maurice Anderson" <mauriceanderson@hotmail.com> wrote in message 
news:43b72c70$1@newsgroups.borland.com...

> 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.

> 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 http://www.deja.com and 
search the newsgroup archives.  Sample code has been posted many many times 
before.

> 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.

> 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.

> 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.

> 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
#2878
Author: Remy Lebeau (TeamB)
Date: Mon, 02 Jan 2006 22:50
14 lines
1460 bytes
"Bob Gonder" <notbg@notmindspring.invalid> wrote in message 
news:thjer1h3bk668mqjsldbil598c69mo46po@4ax.com...

>>  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
#2879
Author: Remy Lebeau (TeamB)
Date: Mon, 02 Jan 2006 22:53
22 lines
1808 bytes
"Maurice Anderson" <mauriceanderson@hotmail.com> wrote in message 
news:43b753c8$1@newsgroups.borland.com...

> Hello Bob, I updated my code with your suggestions but to no avail

Those changes were unnecessary.

> 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.

> 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 
Thread Navigation

This is a paginated view of messages in the thread with full content displayed inline.

Messages are displayed in chronological order, with the original post highlighted in green.

Use pagination controls to navigate through all messages in large threads.

Back to All Threads