Link to home
Start Free TrialLog in
Avatar of Olympus
Olympus

asked on

File transfer over sockets?

What are other good ways of sending a file across sockets by not using SendStream and not loading a whole filestream into a pointer and sending it? (im not using TClientSocket, im using WSOcket)

--Olympus
Avatar of Olympus
Olympus

ASKER

Adjusted points from 3 to 50
code from williams2 to send the screen..
just replace TMemoryStream for TFileStream



                         Server:
                         unit Unit1;

                         interface

                         uses
                           Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
                           ExtCtrls, StdCtrls, ExtDlgs, WSocket, Winsock;

                         Const
                           //You may set this to False if you would like the whole image!
                           STRETCH = True;
                           STRETCH_WIDTH = 200;
                           STRETCH_HEIGHT = 150;

                         type
                           TForm1 = class(TForm)
                             WSocket1: TWSocket;
                             procedure FormCreate(Sender: TObject);
                           private
                         //    ServerSocket1: TServerSocket;
                             SrvSocket,
                             CliSocket: TWSocket;
                         //    procedure ServerSocket1ClientRead(Sender: TObject;
                         //      Socket: TCustomWinSocket);
                             procedure SrvSocketSessionAvailable(Sender: TObject; Error: Word);
                             procedure SocketDataAvailable(Sender: TObject; Error: Word);
                           private
                             { Private declarations }
                             Stream: TMemoryStream;
                         //    procedure SendNextPart(Socket: TCustomWinSocket);
                             procedure SendNextPart(Socket: TWSocket);
                           public
                             { Public declarations }
                             Timer: TTimer;
                             procedure OnTime(Sender: TObject);
                         //    procedure SendScreen(Socket: TCustomWinSocket);
                             procedure SendScreen(Socket: TWSocket);
                           protected
                             Bitmap: TBitmap;
                           end;

                         var
                           Form1: TForm1;


                         implementation

                         {$R *.DFM}

                         procedure TForm1.FormCreate(Sender: TObject);
                         begin
                           Bitmap:= TBitmap.Create;
                           if STRETCH then
                           begin
                             Bitmap.Width:= STRETCH_WIDTH;
                             Bitmap.height:= STRETCH_HEIGHT;
                           End else
                           begin
                             Bitmap.Width:= Screen.Width;
                             Bitmap.Height:= Screen.Height;
                           End;
                           Timer:= TTimer.Create(Self);
                           Timer.Interval:= 1000;
                           Timer.OnTimer:= OnTime;
                           Timer.Enabled:= True;
                         {  ServerSocket1:= TServerSocket.Create(Self);
                           With ServerSocket1 do
                           begin
                             Port:= 2500;
                             Active:= True;
                             ServerType:= stNonBlocking;
                             OnClientRead:= ServerSocket1ClientRead;
                           End;}
                           CliSocket:= TWSocket.Create(self);
                           CliSocket.OnDataAvailable:= SocketDataAvailable;
                           SrvSocket:= TWSocket.Create(Self);
                           With SrvSocket do
                           begin
                             Addr              := '127.0.0.1';      { Accept local clients }
                             Port              := '2500';
                             OnSessionAvailable:= SrvSocketSessionAvailable;
                             Listen;                                { Start listening for client }
                           End;
                           Stream:= TMemoryStream.Create;
                         end;

                         procedure TForm1.SrvSocketSessionAvailable(Sender: TObject; Error: Word);
                         var
                             NewHSocket : TSocket;
                         begin
                             { We need to accept the client connection }
                             NewHSocket := SrvSocket.Accept;

                             { And then associate this connection with our client socket }
                             CliSocket.Dup(NewHSocket);
                         end;

                         procedure TForm1.SocketDataAvailable(Sender: TObject; Error: Word);
                         //procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
                         //  Socket: TCustomWinSocket);
                         var
                           S: String;
                           Socket: TWSocket;
                         Begin
                           Socket:= TWSocket(Sender);
                         //  S:= Socket.ReceiveText;
                           S:= Socket.ReceiveStr;
                           If S='Get me the screen' then SendScreen(Socket) else
                           If S='Send next' then SendNextPart(Socket) else
                           If S='Done' then Socket.Close;
                         End;

                         //procedure TForm1.SendScreen(Socket: TCustomWinSocket);
                         procedure TForm1.SendScreen(Socket: TWSocket);
                         var
                           Size: Integer;
                         Begin
                           Bitmap.SaveToStream(Stream);
                           Size:= Stream.Size;
                           Stream.Position:= 0;
                         //  Socket.SendBuf(Size,SizeOf(Size));
                           Socket.Send(@Size,SizeOf(Size));
                         End;

                         //procedure TForm1.SendNextPart(Socket: TCustomWinSocket);
                         procedure TForm1.SendNextPart(Socket: TWSocket);
                         const
                           MaxChunkSize = 8192; { copy in 8K chunks }
                         var
                           ChunkSize: Integer;
                           CopyBuffer: Array[0..MaxChunkSize] of Byte;
                         Begin
                           Chunksize:= Stream.Size-Stream.Position;
                           If ChunkSize>0 then
                           begin
                             If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
                             Stream.Read(CopyBuffer,ChunkSize);
                             Socket.Send(@CopyBuffer,ChunkSize);
                         //    Socket.SendBuf(CopyBuffer,ChunkSize);
                           End else
                             Stream.Clear; //The final
                         End;

                         procedure TForm1.OnTime(Sender: TObject);
                         var
                           dwRop: DWord;
                           DC: hDC;
                         begin
                           dwRop:= SRCCOPY;
                           DC:= GetDC(0);
                           If STRETCH then
                             StretchBlt(
                               Bitmap.Canvas.Handle, // handle to destination device context
                               0, // x-coordinate of destination rectangle's upper-left corner
                               0, // y-coordinate of destination rectangle's upper-left corner
                               Bitmap.Width, // width of destination rectangle
                               Bitmap.Height, // height of destination rectangle
                               DC, // handle to source device context
                               0, // x-coordinate of source rectangle's upper-left corner
                               0, // y-coordinate of source rectangle's upper-left corner
                               Screen.Width, // width of source rectangle
                               Screen.Height, // height of source rectangle
                               dwRop        // raster operation code (See below)
                             )
                           else
                             BitBlt(
                               Bitmap.Canvas.Handle, // handle to destination device context
                               0, // x-coordinate of destination rectangle's upper-left corner
                               0, // y-coordinate of destination rectangle's upper-left corner
                               Bitmap.Width, // width of destination rectangle
                               Bitmap.Height, // height of destination rectangle
                               DC, // handle to source device context
                               0, // x-coordinate of source rectangle's upper-left corner
                               0, // y-coordinate of source rectangle's upper-left corner
                               dwRop        // raster operation code (See below)
                             );
                           ReleaseDC(0,DC)
                         {
                         BLACKNESS Fills the destination rectangle using the color associated with
                         index 0 in the physical palette. (This color is black for the
                                         default physical palette.)
                         DSTINVERT Inverts the destination rectangle.
                         MERGECOPY Merges the colors of the source rectangle with the specified
                         pattern by using the Boolean AND operator.
                         MERGEPAINT Merges the colors of the inverted source rectangle with the
                         colors of the destination rectangle by using the Boolean OR
                                         operator.
                         NOTSRCCOPY Copies the inverted source rectangle to the destination.
                         NOTSRCERASE Combines the colors of the source and destination rectangles
                         by using the Boolean OR operator and then inverts the resultant
                                         color.
                         PATCOPY Copies the specified pattern into the destination bitmap.
                         PATINVERT Combines the colors of the specified pattern with the colors of
                         the destination rectangle by using the Boolean XOR operator.
                         PATPAINT Combines the colors of the pattern with the colors of the
                         inverted source rectangle by using the Boolean OR operator. The
                                         result of this operation is combined with the colors of the
                                         destination rectangle by using the Boolean OR operator.
                         SRCAND Combines the colors of the source and destination rectangles
                         by using the Boolean AND operator.
                         SRCCOPY Copies the source rectangle directly to the destination
                         rectangle.
                         SRCERASE Combines the inverted colors of the destination rectangle with
                         the colors of the source rectangle by using the Boolean AND operator.
                         SRCINVERT Combines the colors of the source and destination rectangles
                         by using the Boolean XOR operator.
                         SRCPAINT Combines the colors of the source and destination rectangles by
                         using the Boolean OR operator.
                         WHITENESS Fills the destination rectangle using the color associated with
                         index 1 in the physical palette. (This color is white for the
                                         default physical palette.)
                         }
                         End;

                         end.


                         Client:
                         unit Unit1;

                         interface

                         uses
                           Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
                           StdCtrls, ExtCtrls, ComCtrls, WSocket;

                         type
                           TForm1 = class(TForm)
                             WSocket1: TWSocket;
                             procedure FormCreate(Sender: TObject);
                           private
                             { Private declarations }
                             ProgressBar: TProgressBar;
                             Button1: TButton;
                             Button2: TButton;
                         //    ClientSocket1: TClientSocket;
                             Image1: TImage;
                             Label1: TLabel;
                             CliSocket: TWSocket;
                             procedure Button1Click(Sender: TObject);
                             procedure Button2Click(Sender: TObject);
                         {    procedure ClientSocket1Connect(Sender: TObject;
                               Socket: TCustomWinSocket);
                             procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
                               ErrorEvent: TErrorEvent; var ErrorCode: Integer);
                             procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
                             procedure ClientSocket1Disconnect(Sender: TObject;
                               Socket: TCustomWinSocket);}
                             procedure CliSocketSessionConnected(Sender: TObject; Error: Word);
                             procedure CliSocketSessionClosed(Sender: TObject; Error: Word);
                             procedure CliSocketDataAvailable(Sender: TObject; Error: Word);
                             procedure CliSocketError(Sender: TObject);
                           private
                             Stream: TMemoryStream;
                           public
                             Procedure UpdateProgressBar;
                           protected
                             Bitmap: TBitmap;
                             Receiving: Boolean;
                             FSize: Integer;
                           end;

                         var
                           Form1: TForm1;

                         implementation

                         {$R *.DFM}

                         procedure TForm1.Button1Click(Sender: TObject);
                         begin
                           Label1.Caption:= 'Connecting..';
                         //  ClientSocket1.Open;
                           CliSocket.Addr   := 'localhost';        { Server host name              }
                           CliSocket.Proto  := 'tcp';              { Protocol we wants to use      }
                           CliSocket.Port   := '2500';             { The port we wants to connect  }
                           CliSocket.Connect;                      { Let's connect !               }
                           { Connect is just a request, it returns immediately. We eventually gets }
                           { gets connected later. At that time we will receive the event          }
                           { SessionConnected. If you need a timeout, you have to start a TTimer.  }
                         end;

                         //procedure TForm1.ClientSocket1Connect(Sender: TObject;
                         //  Socket: TCustomWinSocket);
                         procedure TForm1.CliSocketSessionConnected(Sender: TObject; Error: Word);
                         begin
                           Label1.Caption:= 'Connected';
                           Receiving:= False;
                           FSize:= 0;
                         end;

                         //procedure TForm1.ClientSocket1Error(Sender: TObject;
                         //  Socket: TCustomWinSocket; ErrorEvent: TErrorEvent;
                         //  var ErrorCode: Integer);
                         procedure TForm1.CliSocketError(Sender: TObject);
                         begin
                           ShowMessage('Did you startup the server? I cannot find it!');
                         end;


                         procedure TForm1.Button2Click(Sender: TObject);
                         begin
                         //  if ClientSocket1.Active then
                         //    ClientSocket1.Socket.SendText('Get me the screen');
                           CliSocket.SendStr('Get me the screen');
                         end;

                         procedure TForm1.FormCreate(Sender: TObject);
                         begin
                           Label1:= TLabel.Create(Self);
                           Label1.SetBounds(32,72,32,13);
                           Label1.Parent:= Self;
                           Label1.Caption:= 'Idle..';
                           Button1:= TButton.Create(Self);
                           Button1.SetBounds(8,8,75,25);
                           Button1.Parent:= Self;
                           Button1.Caption:= 'Connect';
                           Button1.OnClick:= Button1Click;
                           Button2:= TButton.Create(Self);
                           Button2.SetBounds(8,40,75,25);
                           Button2.Parent:= Self;
                           Button2.Caption:= 'Get screen';
                           Button2.OnClick:= Button2Click;
                         {  ClientSocket1:= TClientSocket.Create(Self);
                           With ClientSocket1 do
                           begin
                             Active := False;
                             ClientType := ctNonBlocking;
                             Port := 2500;
                             Address := '127.0.0.1';
                             OnConnect := ClientSocket1Connect;
                             OnDisconnect := ClientSocket1Disconnect;
                             OnRead := ClientSocket1Read;
                             OnError := ClientSocket1Error;
                           end;}
                           CliSocket:= TWSocket.Create(Self);
                           With CliSocket do
                           begin
                             OnSessionConnected:= CliSocketSessionConnected;
                             OnSessionClosed:= CliSocketSessionClosed;
                             OnDataAvailable:= CliSocketDataAvailable;
                             OnError:= CliSocketError;
                           //  CliSocket.
                           End;
                           Image1:= TImage.Create(Self);
                           Image1.SetBounds(100,0,0,0);
                           Image1.AutoSize:= true;
                           Image1.Parent:= Self;

                           Stream:= TMemoryStream.Create;
                           ProgressBar:= TProgressBar.Create(Self);
                           ProgressBar.Min:= 0;
                           ProgressBar.Align:= alBottom;
                           ProgressBar.Parent:= Self;
                         end;

                         Procedure TForm1.UpdateprogressBar;
                         Begin
                           ProgressBar.Position:= ProgressBar.Max-FSize;
                           progressBar.Update;
                         End;

                         //procedure TForm1.ClientSocket1Read(Sender: TObject;
                         //  Socket: TCustomWinSocket);
                         procedure TForm1.CliSocketDataAvailable(Sender: TObject; Error: Word);
                         const
                           MaxChunkSize = 8192; { copy in 8K chunks }
                         var
                           BytesReceived: Longint;
                           CopyBuffer: Array[0..MaxChunkSize] of Byte; { buffer for copying }
                           ChunkSize: Integer;
                           TempSize: Integer;
                         begin
                           If FSize=0 then
                           begin
                         //    If Socket.ReceiveLength>=SizeOf(TempSize) then
                             If CliSocket.RcvdCount>=SizeOf(TempSize) then
                             begin
                         //      Socket.ReceiveBuf(TempSize,SizeOf(TempSize)); //get the size
                               CliSocket.Receive(@TempSize,SizeOf(TempSize));
                         //      Socket.ReceiveBuf(TempSize,SizeOf(TempSize)); //get the size
                               Stream.SetSize(TempSize);
                               Stream.Position:= 0;
                               ProgressBar.Max:= TempSize;
                               FSize:= TempSize; //Threadsafe code!
                             End;
                           End;
                           If (FSize>0) and not(Receiving) then
                           begin
                             Receiving:= True;
                         //    While Socket.ReceiveLength>0 do
                             While CliSocket.RcvdCount>0 do
                             Begin
                         //      ChunkSize:= Socket.ReceiveLength;
                               ChunkSize:= CliSocket.RcvdCount;
                               If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
                         //      BytesReceived:= Socket.ReceiveBuf(CopyBuffer,ChunkSize);
                               BytesReceived:= CliSocket.Receive(@CopyBuffer,ChunkSize);
                               Stream.Write(CopyBuffer, BytesReceived); { ...write chunk }
                               Dec(FSize,BytesReceived);
                               UpdateProgressBar;
                             End;
                             //This is called "to Syncronize trasnsmissions"
                         //    Socket.SendText('Send next');
                             CliSocket.SendStr('Send next');
                             If FSize=0 then
                             begin
                         //      Socket.SendText('Done');
                               CliSocket.SendStr('Done');
                               Stream.Position:= 0;
                               Image1.Picture.Bitmap.LoadFromStream(Stream);
                               FSize:= 0;
                               ProgressBar.Position:= 0;
                               Stream.Clear;
                             End;
                             Receiving:= False;
                           End;
                         end;


                         //procedure TForm1.ClientSocket1Disconnect(Sender: TObject;
                         //  Socket: TCustomWinSocket);
                         procedure TForm1.CliSocketSessionClosed(Sender: TObject; Error: Word);
                         begin
                           Label1.Caption:= 'Disconnected';
                         end;

                         end.
Avatar of Olympus

ASKER

this is a rather rudimentary method, i want something simple but effective like this:
var
P: Pointer;
FS: TFileStream;
begin
FS := TFileStream.Create('c:\windows\calc.exe', fmOpenRead or fmShareDenyNone);
GetMem(P, FS.Size);
FS.Read(P, FS.Size);
WSocket1.Send(P, SizeOf(P));
FreeMem(P);
FS.Free;
end;

but inwhich the server does not load the whole file into memory (500 megs?)
you can't send more than 8kb at a time..
and using TFileStream with the demo I posted .. it doesn't load the complete file then 8kb each time..

I'm sorry.. I'm almost 100% sure you can't send the file at once.. 8kb at a time ..
Avatar of Olympus

ASKER

no that code works, i just want some code that doesnt load the whole thing into memory.
tell me, would something like this work:

var
  fs: TFileStream;
  p: Pointer;
begin
  fs:=TFileStream.Create('c:\config.sys', fmOpenRead);
  GetMem(p, 8192);
  while fs.Position < fs.Size do
  begin
    fs.Read(p, 8192);
    WSocket1.Send(p, SizeOf(p));
  end;
  fs.Free;
end;

from what ive read that would screw it up right?
i need something like that, in one function thats sends a file without loading it into memory all at once like my previous example...
using that.. I think the buffer would be overloaded.. I don't know..
did you try ?
Avatar of Olympus

ASKER

that doesnt work...
ASKER CERTIFIED SOLUTION
Avatar of bryan7
bryan7
Flag of Japan image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Olympus

ASKER

Comment accepted as answer