Using TCPIP manually

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.