Newsgroups : Borland : borland.public.delphi.internet.winsock : 2006 Aug : Re: Problem reading data from TidIOHandler
| Subject: | Re: Problem reading data from TidIOHandler |
| Posted by: | "Remy Lebeau (TeamB)" (no.spam@no.spam.com) |
| Date: | Tue, 15 Aug 2006 13:16:02 |
"Kiwi" <glen@custommadesoftware.co.nz> wrote in message
news:44e14282@newsgroups.borland.com...
> I am still having problems handling the data from the IOHandler
That is because you are still not handling it correctly.
> Here is the Server side code which seems to be working fine
Wrong. It is not working correctly, because of the following ...
> Buf:= RawToBytes(fMem, fMem.Size);
That line is wrong. As I explained to you earlier, in order to access the
TMemoryStream's content, you must use its Memory property, ie:
Buf := RawToBytes(fMem.Memory, fMem.Size);
You are not doing that, so you are trying to convert the raw data that is
located at the memory address where the TMemoryStream object itself is
stored, not where its data buffer is stored. The two are NOT at the same
memory address!
> Move(Buf[0], Buf[4], Length(Buf));
That is also wrong. You are writing data past the end of the buffer, so you
are going to corrupt the surrounding memory, if not cause an AV instead.
Since you are using the new length instead of the original length, you need
to subtract 4 when copying the bytes:
Move(Buf[0], Buf[4], Length(Buf)-4);
> BytesToRaw(Buf, fMem, Size);
> fMem.Position:= 0; <=====Failing here with an access violation
That is because you are still overwriting the value stored in the
TMemoryStream pointer incorrectly, as I explained to you earlier. You MUST
set the TMemoryStream's Size property and then copy the bytes into the
TMemoryStream's Memory property instead, ie:
fMem.Size := Size;
BytesToRaw(Buf, fMem.Memory, Size);
With that said, you shouldn't be trying to stuff the TIdBytes length into
the TIdBytes itself to begin with. Use the Write(Integer) and ReadInteger()
methods instead, ie:
--- server ---
Buf := RawToBytes(fMem.Memory, fMem.Size);
AContent.Connection.IOHandler.Write(Integer(Length(Buf)));
AContext.Connection.IOHandler.Write(Buf);
--- client ---
fMem := TMemoryStream.Create;
try
SetLength(Buf, 0);
Size := IOHandler.ReadInteger;
if Size > 0 then IOHandler.ReadBytes(Buf, Size, False);
fMem.Size := Size;
BytesToRaw(Buf, fMem.Memory, Size);
fMem.Position := 0;
fMem.Read(cmd, 4);
finally
fMem.Free;
end;
Alternatively:
--- server ---
fMem.Position := 0;
ReadTIdBytesFromStream(fMem, Buf, fMem.Size);
AContent.Connection.IOHandler.Write(Integer(Length(Buf)));
AContext.Connection.IOHandler.Write(Buf);
--- client ---
fMem := TMemoryStream.Create;
try
SetLength(Buf, 0);
Size := IOHandler.ReadInteger;
if Size > 0 then IOHandler.ReadBytes(Buf, Size, False);
WriteTIdBytesToStream(fMem, Buf, Size);
fMem.Position := 0;
fMem.Read(cmd, 4);
finally
fMem.Free;
end;
Even better, as I suggested to you earlier, you should get rid of the
TIdBytes altogether and read/write the streams directly. Write(Stream) and
ReadStream() even handle the 4-byte length for you automatically.
--- server ---
AContext.Connection.IOHandler.Write(fMem, 0, True);
--- client ---
fMem := TMemoryStream.Create;
try
IOHandler.ReadStream(fMem, -1, False);
fMem.Position := 0;
fMem.Read(cmd, 4);
finally
fMem.Free;
end;
Gambit
none