Article View: borland.public.cppbuilder.internet.socket
Article #2899Re: TWinSocketStream Read in BYTE buffer
From: Remy Lebeau (TeamB)
Date: Thu, 05 Jan 2006 18:50
Date: Thu, 05 Jan 2006 18:50
268 lines
9916 bytes
9916 bytes
"Maurice Anderson" <mauriceanderson@hotmail.com> wrote in message
news:43bcedb2$1@newsgroups.borland.com...
> Also found an issue in ReadBuf which causes TFileStream *FS
> to write fewer bytes to the file than what is in the stream.
In order to ensure that all data gets written to the file, you have to look
at the return value of TFileStream::Write(), just like you have to with
TWinSocketStream::Write(), so that you know how many bytes were actually
written to the stream. That way, you can call Write() again if needed to
save any remaining unwritten bytes.
The easiest way to do that is to change ReadBuf() and WriteBuf() to take a
TStream* parameter instead of a TWinSocketStream* parameter, since the inner
logic already handles incomplete reads/writes. That way, you can pass both
TWinSocketStream and TFileStream to the same processing code:
bool __fastcall 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 WriteBuf(TStream *Stream, void *Buffer, int BufSize)
{
BYTE *pBuf = (BYTE*) Buffer;
int NumSent;
try
{
while( BufSize > 0 )
{
NumSent = Stream->Write(pBuf, BufSize);
if( NumSent < 1 )
return false;
pBuf += NumSent;
BufSize -= NumSent;
}
}
catch(const Exception &)
{
return false;
}
return true;
}
Then you can update ReadFile() and SendFile() accordingly:
bool __fastcall SendFile(TWinSocketStream *Stream, const AnsiString
&FileName)
{
bool error = false;
try
{
TFileStream *FS = new TFileStream(FileName, fmOpenRead |
fmShareDenyWrite);
try
{
char type = 0x02;
if( WriteBuf(Stream, &type, sizeof(char)) )
{
if( WriteString(Stream, ExtractFileName(FileName)) )
{
int size = FS->Size;
if( WriteBuf(Stream, &size, sizeof(int)) )
{
BYTE rbuf[256];
int bufsize;
while( size > 0 )
{
bufsize = size;
if( bufsize > sizeof(rbuf) )
bufsize = sizeof(rbuf);
if( !ReadBuf(FS, rbuf, bufsize) ) // <--
here
{
error = true;
break;
}
if( !WriteBuf(Stream, rbuf, bufsize) )
{
error = true;
break;
}
size -= bufsize;
}
}
}
}
}
__finally
{
delete FS;
}
}
catch(const Exception &)
{
error = true;
}
return !error;
}
bool __fastcall ReadFile(TWinSocketStream *Stream, AnsiString &FileName)
{
AnsiString fn;
if( ReadString(Stream, fn) )
{
fn = ("C:\\Some Folder\\" + ExtractFileName(fn));
int size = 0;
if( ReadBuf(Stream, &size, sizeof(int)) )
{
bool error = false;
try
{
TFileStream *FS = new TFileStream(fn, fmCreate);
try
{
FS->Size = size;
FS->Position = 0;
BYTE rbuf[256];
int bufsize;
while( size > 0 )
{
bufsize = size;
if( bufsize > sizeof(rbuf) )
bufsize = sizeof(rbuf);
if( !ReadBuf(Stream, rbuf, bufsize) )
{
error = true;
break;
}
if( !WriteBuf(FS, rbuf, bufsize) ) // <-- here
{
error = true;
break;
}
size -= bufsize;
}
}
__finally
{
delete FS;
}
}
catch(const Exception &)
{
error = true;
DeleteFile(fn);
}
if( !error )
{
FileName = fn;
return true;
}
}
}
return false;
}
> (5) So ReadBuf is called 249 times to read 63,744 Bytes.
> And each time ReadBuf returns, FS faithfully writes the contents
> to itself the same 249 times. This leaves the last 76 Bytes to go.
That is not a correct assessment.
The size value that ReadFile() receives will indicate the full size of the
file. In this case, the size should be coming through as 63820, not 63744.
ReadFile() will keep reading until all 63,820 bytes have been received.
That is because of this line:
while( size > 0 )
The size of the buffer being used does not matter. In this case, since the
buffer size is 256, after 249 iterations of the loop, the size variable will
be 76, and ReadFile() will then read the last 76 bytes instead of 256 bytes
and then exit the loop since the size variable falls to 0.
> (7) You see, once the Stream reads those 76 Bytes into pBuf, it cycles
> back once more. On this last cycle in encounters 0 bytes to read
> so it kicks back a false as the return variable:
That is not a correct assessment, either.
On input, the BufSize parameter is set to 76. ReadBuf() loops only as long
as there is data expected to be received:
while( BufSize > 0 )
Every time pStream->Read() returns without error, the actual number of bytes
received is substracted from the BufSize parameter:
BufSize -= NumRead;
After 76 bytes have eventually been received, the BufSize parameter has
fallen to 0 and the loop exits without calling pStream->Read() again. At
which time, a 'true' value is returned, not 'false'.
> if( !ReadBuf(rbuf, bufsize) )
> {
> error = true;
> break; < - exists loop with 76
bytes
> left in rBuf
> }
No, it does not. ReadBuf() return true, not false, on the last 76 bytes.
> if( FS->Write(rbuf, bufsize) < 1 ) <- Never
sees
> the last 76 bytes
> {
Yes, it will.
> (10) To resolve this I change around ReadBuf to return the number of
> bytes read. If the bytes read from ReadBuf are < 1, then I kick
> out of the while loop.
You should not have done that. There is nothing wrong with the ReadBuf()
code I have given you.
Not only that, but you have introduced bugs into ReadBuf() now. If
successful, you are returning a hard-coded 256 rather than the number of
bytes actually read. If failed, you are returning the number of bytes
received in the last read, not the total number of bytes received before the
error occured.
Gambit
Technical Details
Message-ID:
<43bd69da$1@newsgroups.borland.com>Path:
arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!news4.google.com!news.glorb.com!meganewsservers.com!feeder2.on.meganewsservers.com!news-out.superfeed.net!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mailReferences:
<43ac3d34$1@newsgroups.borland.com> <43ac6028$1@newsgroups.borland.com> <43acc4c5$1@newsgroups.borland.com> <43ae5b51$1@newsgroups.borland.com> <43aeebe1$1@newsgroups.borland.com> <43aef70e$1@newsgroups.borland.com> <43af06d7$1@newsgroups.borland.com> <43b252fa$1@newsgroups.borland.com> <43b43a5a$1@newsgroups.borland.com> <43b45550$1@newsgroups.borland.com> <43b5a868$1@newsgroups.borland.com> <43b9b1b0$2@newsgroups.borland.com> <43bcedb2$1@newsgroups.borland.com>Show Full Headers
Complete Article Headers
X-Google-Thread: 11508e,74cdc31c66b3abd9 X-Google-Attributes: gid11508e,public X-Google-Language: ENGLISH,ASCII-7-bit From: "Remy Lebeau \(TeamB\)" <no.spam@no.spam.com> Newsgroups: borland.public.cppbuilder.internet.socket References: <43ac3d34$1@newsgroups.borland.com> <43ac6028$1@newsgroups.borland.com> <43acc4c5$1@newsgroups.borland.com> <43ae5b51$1@newsgroups.borland.com> <43aeebe1$1@newsgroups.borland.com> <43aef70e$1@newsgroups.borland.com> <43af06d7$1@newsgroups.borland.com> <43b252fa$1@newsgroups.borland.com> <43b43a5a$1@newsgroups.borland.com> <43b45550$1@newsgroups.borland.com> <43b5a868$1@newsgroups.borland.com> <43b9b1b0$2@newsgroups.borland.com> <43bcedb2$1@newsgroups.borland.com> Subject: Re: TWinSocketStream Read in BYTE buffer Date: Thu, 5 Jan 2006 10:50:09 -0800 Lines: 270 X-Priority: 3 X-MSMail-Priority: Normal X-Newsreader: Microsoft Outlook Express 6.00.2800.1409 X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1409 NNTP-Posting-Host: 68.69.17.41 Message-ID: <43bd69da$1@newsgroups.borland.com> X-Trace: newsgroups.borland.com 1136486874 68.69.17.41 (5 Jan 2006 10:47:54 -0700) Path: arc1-ca.pugleaf.net!g2news1.google.com!news2.google.com!news4.google.com!news.glorb.com!meganewsservers.com!feeder2.on.meganewsservers.com!news-out.superfeed.net!propagator2-sterling.newsfeeds.com!in.nntp.be!caladan.landsraad.net!newsgroups.borland.com!not-for-mail