🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: borland.public.cppbuilder.internet.socket
7 messages
7 total messages Started by Vladimir Stefanovic Thu, 19 Aug 2004 07:01
Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5353
Author: Vladimir Stefanovic
Date: Thu, 19 Aug 2004 07:01
129 lines
4911 bytes
Hi, (please don't be discourraged when you see the code :)

I made a simple test program for sending TMemoryStream from
TCS to TSS. The bytes has been sent but the destination copy
is usually mixed and/or damaged in some parts.

I used ctBlocking & stNonBlocking modes. When ctNonBlocking &
stThreadBlocking, the example does not work at all (which is
probably normal).

* What can I do to preserve the data consistency at the
destination?

* What is the common BUFFER_SIZE, and is there any need for it
to be configurable?

* Is there any good example/artcile/web for all these possible
techiques of sending data?


--- CLIENT SIDE ---

__fastcall TclientForm::TclientForm(TComponent* Owner)
        : TForm(Owner)
{
   OutboxDataBuffer = new TMemoryStream;
   OutboxDataBuffer->LoadFromFile( ExtractFilePath( ParamStr(0) ) + "test.txt" );
}

__fastcall TclientForm::~TclientForm()
{
   delete OutboxDataBuffer;
}

const int BUFFER_SIZE = 100;

void __fastcall TclientForm::SendButtonClick(TObject *Sender)
{
    // buffer to accept portions of the memory stream...
    BYTE Buffer [ BUFFER_SIZE ];

    // current position of sent data...
    int CurrentPosition = 0;

    // needed to calculate the size of buffer because the last portion/s is/are usually smaller...
    int Delta;

    // while current sent position hasn't yet achieved the memory stream size...
    while ( ( Delta = OutboxDataBuffer->Size - CurrentPosition ) > 0 )
    {
       // should I use the full buffer size or truncated because of last portion...
       int NumberOfBytesRead = ( Delta < BUFFER_SIZE ? Delta : BUFFER_SIZE );

       // positions memory stream to the last sent position...
       OutboxDataBuffer->Seek( CurrentPosition, soFromBeginning );

       // reads the previously calculated amount of bytes from memory stream...
       OutboxDataBuffer->ReadBuffer( Buffer, NumberOfBytesRead );

       // send the buffer and give me the actually sent bytes
       int NumberOfBytesSent = ClientSocket->Socket->SendBuf( Buffer, NumberOfBytesRead );

       // if the number of sent bytes is less then ZERO it's an error...
       if ( NumberOfBytesSent < 1 )
       {
          return; // Error ...
       }

       // our new position is incresed by number of bytes actually sent...
       CurrentPosition += NumberOfBytesSent;
    }
}


--- SERVER SIDE ---

__fastcall TserverForm::TserverForm(TComponent* Owner)
        : TForm(Owner)
{
   InboxDataBuffer = new TMemoryStream;
}

__fastcall TserverForm::~TserverForm()
{
   delete InboxDataBuffer;
}

const int TOTAL_SIZE = 44800; // Expected file length in bytes

void __fastcall TserverForm::ServerSocketClientRead(TObject *Sender,
      TCustomWinSocket *Socket)
{
    // how many bytes are read in this pass...
    int IncomingSize = Socket->ReceiveLength();

    // check if any data is available to read at all...
    if ( IncomingSize < 1 ) return;

    // read how many bytes have already been stored into buffer...
    int OldSize = InboxDataBuffer->Size;

    // calculate the new size that has to be into buffer after receiving...
    int NewSize = OldSize + IncomingSize;

    // increse the size of the buffer to allow the new storage...
    InboxDataBuffer->Size = NewSize;

    // read the incoming data into the buffer...
    Socket->ReceiveBuf( InboxDataBuffer->Memory, IncomingSize );

    // check if the whole amount of data has been received...
    if ( NewSize == TOTAL_SIZE )
    {
       // increse the size of the buffer to allow the new storage...
       InboxDataBuffer->Size = NewSize;
       
       // resets the stream position to beginning (maybe this is not necessary)...
       InboxDataBuffer->Position = 0;
       
       // unfortunately, receiving finished with some mess into Copy.txt...
       InboxDataBuffer->SaveToFile( ExtractFilePath( ParamStr(0) ) + "Copy.txt" );
    }
}



Best regards,
Vladimir Stefanovic
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5355
Author: Remy Lebeau (TeamB)
Date: Thu, 19 Aug 2004 16:40
20 lines
1525 bytes
"Vladimir Stefanovic" <antivari@ptt.yu> wrote in message
news:41245031$1@newsgroups.borland.com...

> The bytes has been sent but the destination copy
> is usually mixed and/or damaged in some parts.

That is because when your server is receiving new data, it is overwriting
the existing buffered data instead of appending the new data to the end of
the buffer.  You need to change this line:

    Socket->ReceiveBuf( InboxDataBuffer->Memory, IncomingSize );

To this instead:

    Socket->ReceiveBuf( &((LPBYTE)(InboxDataBuffer->Memory))[OldSize],
IncomingSize );


Gambit
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5356
Author: Vladimir Stefanovic
Date: Thu, 19 Aug 2004 18:34
27 lines
1481 bytes
Uh, I hope this will work. I'm not curerntly at PC with BCB, so I'll
try this tomorrow.

Thanks a lot Remy. My productivity has increased many times
when I discovered these NGs, and primarily with your
assistence and suggestions.


Best regards,
Vladimir Stefanovic



>  You need to change this line:
>
>     Socket->ReceiveBuf( InboxDataBuffer->Memory, IncomingSize );
>
> To this instead:
>
>     Socket->ReceiveBuf( &((LPBYTE)(I
nboxDataBuffer->Memory))[OldSize],
> IncomingSize );
>
>
> Gambit
>
>
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5358
Author: Vladimir Stefanovic
Date: Fri, 20 Aug 2004 08:47
78 lines
3598 bytes
>Uh, I hope this will work

Yes, It worked perfectly...

I have read one of your posts some time ago...

> the client-side code you currently have will not work
> as-is if you are using non-blocking mode, because you
> are not checking for when SendBuffer() fails to send
> any data due to blocking.  When that happens, you have
> to wait for the OnWrite event to trigger before you can
> send more data again.  Otherwise, you are going to corrupt
> your data stream because not all of the data will be sent
> correctly.

... and I have the same situation in NonBlocking mode. How
can I addopt the code I have, to work synchronized with
OnWrite(), or I have to take a completely different approach?

Should that change also affect the servers receiving mechanism?

   BYTE Buffer [ BUFFER_SIZE ];
   int CurrentPosition = 0;
   int Delta;
   while ( ( Delta = OutboxDataBuffer->Size - CurrentPosition ) > 0 )
   {
      int NumberOfBytesRead = ( Delta < BUFFER_SIZE ? Delta : BUFFER_SIZE );
      OutboxDataBuffer->Seek( CurrentPosition, soFromBeginning );
      OutboxDataBuffer->ReadBuffer( Buffer, NumberOfBytesRead );
      int NumberOfBytesSent = ClientSocket->Socket->SendBuf( Buffer, NumberOfBytesRead );
      if ( NumberOfBytesSent < 1 ) // <--- this happens in non-blocking mode after 8K
         return; // Error ...
      CurrentPosition += NumberOfBytesSent;
    }


Just one more thing:

I thought that within Open/Close...

   ClientSocket->Open()
      ClientSocket->Socket->SendBuf()
   ClientSocket->Close()   

... I am addressing the same unique ServerSocketClientRead
instance:
 
   void __fastcall TserverForm::ServerSocketClientRead(TObject *Sender,
         TCustomWinSocket *Socket)
   {
      // ...
      int NewSize;
      // ... NewSize increases ...
      this->Caption = IntToStr ( NewSize );
   }

... but when Closed() and again Opened(), 'NewSize' continues
counting like it is static! In fact 'NewSize' continues counting
for all clients' connections when sending. I realize that this
must have some sense and I'm trying to figure it out. Is that
in connection with servers' blocking modes?

All this I need to find out the way how to:

* Deploy and recognize connection of a speciffic client and
somehow make it's own TMemoryStream for receiving, decoding
and adding to the shared list (with critical section involved).

* Inform the server what stream size to expect (embed that
into stream, for example first 10 bytes ASCII, or a separate
call)




Best regards,
Vladimir Stefanovic
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5361
Author: Vladimir Stefanovic
Date: Fri, 20 Aug 2004 13:44
95 lines
3242 bytes
> Is that in connection with servers' blocking modes?

Hi Remy,

I think I finally discovered the right way to connect to server
and not to think of the common OnRead().

I just do not know yet the best way to inform the server of
the expecting data size. Can I somehow involve TMemoryStream
in this code and so the final TMemoryStream::Size is the size
I expected?

Ig I have to imnform the server of the stream size separately,
how the server knows to whome is the received size addressed?


In this code I explicitely said that I want 44800 bytes.

[code is based on your samples in these ng-s]

void __fastcall TsrvForm::ServerSocketGetThread(TObject *Sender,
      TServerClientWinSocket *ClientSocket,
      TServerClientThread *&SocketThread)
{
   SocketThread = new TLanServerThread( false, ClientSocket );
}

void __fastcall TLanServerThread::ClientExecute()
{
   char *SomeBuffer = new char[44800];
   int BufferSize = 44800;

   TWinSocketStream *Stream = new TWinSocketStream ( ClientSocket,
5000 );

   try
   {
      while( ( !Terminated ) && ( ClientSocket->Connected ) )
      {
         if ( Stream->WaitForData ( 5000 ) )
         {
            if( !ReadData ( Stream, SomeBuffer, BufferSize ) )
               break;

            // use your buffered data as needed...
            FILE *p;
            AnsiString File = ExtractFilePath( ParamStr(0) ) +
"Copy.txt";
            p = fopen( File.c_str(), "wb+" );
            fwrite ( SomeBuffer, 1, 44800, p );
            fclose (p);
         }
      }
   }
   __finally
   {
      delete Stream;
      delete SomeBuffer;
   }

}

bool __fastcall TLanServerThread::ReadData( TWinSocketStream *Stream,
void *Buffer, int BufferSize )
{

   LPBYTE Buf = (LPBYTE)Buffer;
   int NumRead, TotalRead = 0;

   try
   {
      while ( TotalRead < BufferSize )
      {
         NumRead = Stream->Read( &Buf[TotalRead],
BufferSize-TotalRead );
         if( NumRead > 0 )
            TotalRead += NumRead;
         else
            return false;

      }
   }
   catch ( const Exception& )
   {
      return false;
   }

   return true;

}



Best regards,
Vladimir Stefanovic
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5363
Author: Remy Lebeau (TeamB)
Date: Fri, 20 Aug 2004 18:26
49 lines
2438 bytes
"Vladimir Stefanovic" <spam@not.needed> wrote in message
news:41260071@newsgroups.borland.com...

> I just do not know yet the best way to inform the
> server of the expecting data size.

Just write the data's size to the socket before writing the actual data, and
then read the size before reading the data, ie:

    int size = the data size;
    ...->SendBuf(&size, sizeof(int));
    ...->SendBuf(buffer, size);

    //...

    void __fastcall TLanServerThread::ClientExecute()
    {
        TWinSocketStream *Stream = new TWinSocketStream(ClientSocket, 5000);
        try
        {
            while( (!Terminated) && (ClientSocket->Connected) )
            {
                if( Stream->WaitForData (5000) )
                {
                    int size = 0;
                    if( !ReadData(Stream, &size, sizeof(int)) )
                        break;

                    char *buffer = new char[size];
                    try
                    {
                        if( ReadData(Stream, buffer, size) )
                            // use your buffered data as needed...
                    }
                    __finally {
                        delete[] buffer;
                    }
                }
            }
        }
        __finally
        {
            delete Stream;
        }
    }


Gambit
Re: Problem with sending data with TCS/TSS (data has been received mixed and/or damaged)
#5365
Author: Vladimir Stefanovic
Date: Fri, 20 Aug 2004 18:57
23 lines
1708 bytes
Hi,

Yes, thanks... That's it.

I'm too tired these days to see the obvious solutions.

>                 if( Stream->WaitForData (5000) )
>                 {
>                     int size = 0;
>                     if( !ReadData(Stream, &size, sizeof(int)) )
>                         break;
>
>                     char *buffer = new char[size];
>                     try
>                     {
>                         if( ReadData(Stream, buffer, size) )
>                             // use your buffered data as needed...
>                     }



Best regards,
Vladimir Stefanovic
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