Subject: Re: TCP/IP -TServerSocket, TClientSocket
I fixed the bug!
The problem is that windows does not send my packet when I do a SendBuf
or SendText etc. but it caches the
data and sends either when a certain size or a timeout is reached.
So in my OnClick-procedure of the server,
it sometimes mixed the header and the data in one packet. As I did
not expect that, I did not handle the data
in this packet.
The solution:
The OnClientRead-event of the server creates a command-string. After
I sent the header, I wait till the answer
BEGIN is standing in this command. Then I send my data. The client
does a Socket.SendText('BEGIN') when it
received the header. So it is completely sure that it are different
packets.
An easy solution for an easy problem. BUT a problem very hard to find!...It
took me 6 hours!!! I searched all
the time at a different (the wrong) place.
> I'm establishing a client/server system which is able to transfer
huge
> data e.g. files. For that I'm creating my own protocol (because I
have
> really specific needs, e.g. in addition some data come from
> databases...). Now, I have a test-"server" written that sends a file
to
> the client when you push a key. it does that by sending a header
first
> in which it is written which filename and the size of the FileStream.
> When my client receives this command, it switches to mode "saving
file"
> and pumps the defined number of following bytes into a file.
>
> So far so good. The first time I do it it works, but not the second!
>
> That means the second time, the transfer stops a few hundred (or
> thousand) bytes before 100%. I get no error-message, neither from
the
> server nor from the client...it simply stops and waits and waits
and
> waits. I'm testing around now for lots of hours but don't find a
mistake
> in my source. So I've added it here and hope that perhaps one of
you is
> able to find a mistake in my code.
>
> First the Server (OnClick event of the button):
> ----------------------------------------------------------------------------------------------------------
>
> procedure TForm1.Button1Click(Sender: TObject);
> var
> FS : TFileStream;
> Buf : Array of Char;
> begin
> SetLength(Buf,100);
> FS:=TFileStream.Create('D:\DATEN\CD-Cover\BG -Nightfall
in
> Middle-Earth front.JPG',fmOpenRead or fmShareDenyNone);
>
> StrPCopy(@Buf[0],'TRANSMIT.FILE'+#3+'XXX.jpg'+#3+IntToStr(FS.Size)+#3+#1);
>
> ServerSocket1.Socket.Connections[0].SendBuf(Buf[0],StrLen(@Buf[0]));
> Application.ProcessMessages;
> FS.Seek(0,soFromBeginning);
> ServerSocket1.Socket.Connections[0].SendStream(FS);
> end;
> ----------------------------------------------------------------------------------------------------------
>
> I don't think that the problem is here because I use the standard
> SendStream-Method.
>
> Here the source of the Client (the whole unit):
>
> ----------------------------------------------------------------------------------------------------------
>
> unit Unit1;
>
> interface
>
> uses
> Windows, Messages, SysUtils, Classes, Graphics, Controls,
Forms,
> Dialogs,
> StdCtrls, ScktComp, Gauges;
>
> type
> TForm1 = class(TForm)
> ClientSocket1: TClientSocket;
> Gauge1: TGauge;
> Label1: TLabel;
> Label2: TLabel;
> procedure ClientSocket1Read(Sender: TObject;
Socket:
> TCustomWinSocket);
> procedure ClientSocket1Connect(Sender: TObject;
> Socket: TCustomWinSocket);
> private
> {Private-Deklarationen}
> public
> {Public-Deklarationen}
> end;
>
> TCommCtrl = record
> Command : String;
> Status : Cardinal;
> FS
: TFileStream;
> FTransSize : Cardinal;
> FTransPos : Cardinal;
> end;
>
> const
> ccsNone = 0;
> ccsTransFile = 1;
>
> WorkDir = 'C:\TEMP\';
>
> var
> Form1: TForm1;
>
> CommCtrl : TCommCtrl;
>
> implementation
>
> {$R *.DFM}
>
> procedure TForm1.ClientSocket1Read(Sender: TObject;
> Socket: TCustomWinSocket);
> var
> LocBuf : Array[0..1000000]
of Char;
> ReceiveLength : Integer;
> BufSize : Integer;
> FileName : String;
> s
: String;
> ResI
: Integer;
> begin
> ReceiveLength:=Socket.ReceiveLength;
> if ReceiveLength>High(LocBuf) then Raise Exception.Create('Local
> Buffer too small');
> BufSize:=0; ResI:=0;
> while (BufSize<ReceiveLength) do begin
> ResI:=Socket.ReceiveBuf(LocBuf[BufSize],ReceiveLength);
> if ResI>0 then
> BufSize:=BufSize+ResI;
> end;
> LocBuf[BufSize]:=#0;
> if CommCtrl.Status=ccsNone then begin
> CommCtrl.Command:=CommCtrl.Command+StrPas(@LocBuf[0]);
> if Pos(#1,CommCtrl.Command)>0 then begin
> if Pos('TRANSMIT.FILE'+#3,AnsiUpperCase(CommCtrl.Command))=1
then
> begin
> Delete(CommCtrl.Command,1,14);
> FileName:='';
> while (CommCtrl.Command<>'')
and
> (Copy(CommCtrl.Command,1,1)<>#3) do begin
> FileName:=FileName+Copy(CommCtrl.Command,1,1);
> Delete(CommCtrl.Command,1,1);
> end;
> Delete(CommCtrl.Command,1,1);
> s:='';
> while (CommCtrl.Command<>'')
and
> (Copy(CommCtrl.Command,1,1)<>#1) and
> (Copy(CommCtrl.Command,1,1)<>#2)and
> (Copy(CommCtrl.Command,1,1)<>#3) do begin
> s:=s+Copy(CommCtrl.Command,1,1);
> Delete(CommCtrl.Command,1,1);
> end;
> if s='' then Raise
Exception.Create('No FileSize!');
> CommCtrl.FTransPos:=0;
> Val(s,CommCtrl.FTransSize,ResI);
> if ResI<>0 then
Raise Exception.Create('Invalid
> FileSize-String!');
> CommCtrl.FS:=TFileStream.Create(WorkDir+FileName,fmCreate
or
> fmShareDenyNone);
>
> Gauge1.MinValue:=0;
> Gauge1.MaxValue:=CommCtrl.FTransSize;
> Label1.Caption:=IntToStr(CommCtrl.FTransSize);
>
> CommCtrl.Status:=ccsTransFile;
> end;
> CommCtrl.Command:='';
> end;
> end else if CommCtrl.Status and ccsTransFile>0 then begin
> if CommCtrl.FTransPos+Cardinal(BufSize)<=CommCtrl.FTransSize
then
> begin
> CommCtrl.FTransPos:=CommCtrl.FTransPos+Cardinal(BufSize);
> CommCtrl.FS.Write(LocBuf[0],BufSize);
>
> Gauge1.Progress:=CommCtrl.FTransPos;
> Label2.Caption:=IntToStr(CommCtrl.FTransPos);
> Gauge1.Repaint;
> Label2.Repaint;
>
> if CommCtrl.FTransPos>=CommCtrl.FTransSize
then begin
> CommCtrl.Status:=ccsNone;
> try CommCtrl.FS.Destroy;
except end;
> end;
> end else begin
> CommCtrl.Status:=ccsNone;
> try CommCtrl.FS.Destroy; except
end;
> Raise Exception.Create('FileStream
longer than file!');
> end;
> end else begin
> CommCtrl.Status:=ccsNone;
> CommCtrl.Command:='';
> end;
> end;
>
> procedure TForm1.ClientSocket1Connect(Sender: TObject;
> Socket: TCustomWinSocket);
> begin
> CommCtrl.Status:=ccsNone;
> end;
>
> end.
> ------------------------------------------------------------------------------------------------------
>
> I use Delphi 4 C/S.