We help IT Professionals succeed at work.

trivia FTP using ICS

joepezt
joepezt asked
on
hi!

is there any easy way to transfer files by using Twsocket (ICS), i am NOT Talking about the ftp component!, and i am not interrested in indy.

how to do this by sending a stream to the destination

thanx
Comment
Watch Question

Commented:
I'm assuming you're writing both the server AND the client.

Just use TWSocket components in both programs and connect them to each other.

This is a quick solution, you should really write a thorough, and more flexible object(s) to handle the file transfer.

//in a common unit used by client and server

TFileInfo = record  
  Name: string[255];
  Size: integer;
end;

const
  FILE_INFO_SIZE = SizeOf(TFileInfo);


//in the client with a TWSocket component named CliSocket

function SendFile(const FileName: string): boolean;
var
  fi: TFileInfo;
  ms: TMemoryStream;
begin
  result := false;
  try
    if CliSocket.State <> wsConnected then
    begin
      CliSocket.Proto := 'tcp';
      CliSocket.Port  := PortEdit.Text;
      CliSocket.Addr  := ServerEdit.Text;
      CliSocket.Connect;
      while CliSocket.State in [wsConnecting] do
      begin
        Application.ProcessMessages;
        if Application.Terminated then exit;
      end;
    end;
    if CliSocket.State = wsConnected then
    begin
      ms := TMemoryStream.Create;
      ms.LoadFromFile(FileName);
      with fi do
      begin
        Name := Filename;
        Size := ms.Size;
      end;
      CliSocket.Send(@fi,FILE_INFO_SIZE);
      CliSocket.Send(ms.Memory,ms.Size);
      CliSocket.Close;
      ms.Free;
    end;
    result := true;
  except
  end;
end;

//in the server (with a TWSocket named SrvSocket on the form)

procedure TForm1.SrvSocketSessionAvailable(Sender: TObject; Error: Word);
var
  NewCli: TWSocket;
  buf: array [0 to 65535] of byte;
  recd, totalrecd: integer;
  ms: TMemoryStream;
  fi: TFileInfo;
begin
  NewCli := TWSocket.Create(Self);
  NewCli.HSocket := SrvSocket.Accept;
  recd := -1;
  while recd <= 0 do
  begin
    Application.ProcessMessages;
    if Application.Terminated then exit;
    recd := NewCli.Receive(@buf[0],FILE_INFO_SIZE);
  end;
  Move(buf[0],fi,FILE_INFO_SIZE);
  fname := TEMP_DIR + '\' + fi.Name;
  ms := TMemoryStream.Create;
  totalrecd := 0;
  while totalrecd < fi.Size do
  begin
    Application.ProcessMessages;
    if Application.Terminated then exit;
    try
      recd := NewCli.Receive(@buf[0],SizeOf(buf));
    except
      recd := 0;
    end;
    if recd <= 0 then
      break
    else
    begin
      ms.Write(buf[0],recd);
      totalrecd := totalrecd + recd;
    end;
  end;
  ms.SaveToFile(fi.Name);
  ms.Free;
  NewCli.Free;
end;

Commented:
Sorry, ignore the line
  fname := TEMP_DIR + '\' + fi.Name;

Also note that this is a very simple example where
a client makes a new connection to send a single file.
The server is not threaded and so processes each client in turn.

rondi.

Author

Commented:
ok, but does remotehost knows the filesize?. and is it easy writing a resume request =?

Commented:
Are you writing the remote host program ?

Author

Commented:
no, i am trying to make a trivia file transfer, like DCC on IRC

and the method used is random listening port, and 1 connection
the next connection shouyld have another random port (preferably  the next available)

Commented:
Shoulda said so from the get-go.
Sorry, I can't help - don't know a hellova lot about
IRC specs or DCC (whatever that is).

I suggest you look at some of the tech. specs for IRC.

rondi.

Author

Commented:
DCC is not that different, i think you can help me anyway, cause DCC is just an open data socket and as soon as it is connected, it will send  the data, like Trivia FTP, or FTP-Data.

i just need to know how to send and resume..

thanks :)

Author

Commented:
hi!, i have tested your sample, but this seems to be very memory consuming :

how can i just allocate small portions of memory and send it ?

stian ..


unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    clisocket: TWSocket;
    srvsocket: TWSocket;
    Memo1: TMemo;
    Button1: TButton;
    procedure FormCreate(Sender: TObject);
  procedure SrvSocketSessionAvailable(Sender: TObject; Error: Word);
    procedure Button1Click(Sender: TObject);
    procedure clisocketDataAvailable(Sender: TObject; Error: Word);
    procedure clisocketSessionConnected(Sender: TObject; Error: Word);
  private
    { Private declarations }
  public
  fileSize : integer;
  ms: TMemoryStream;
  ms2 : TMemoryStream;
  Procedure SendFile;
end;

var
  Form1: TForm1;


implementation

{$R *.DFM}



procedure TForm1.SrvSocketSessionAvailable(Sender: TObject; Error: Word);
begin
 srvsocket.HSocket := SrvSocket.Accept;
end;


Procedure Tform1.SendFile;
begin
   if CliSocket.State <> wsConnected then
   begin
     CliSocket.Proto := 'tcp';
     CliSocket.Port  := '60';
     CliSocket.Addr  := '127.0.0.1';
     CliSocket.Connect;
   end;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
 srvsocket.Listen;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
 ms := TMemoryStream.Create;
sendfile;
end;

procedure TForm1.clisocketDataAvailable(Sender: TObject; Error: Word);
var
 buf: array [0..65535] of byte;
 recd, totalrecd: integer;
begin
 recd := -1;
 while recd <= 0 do
 begin
   Application.ProcessMessages;
   if Application.Terminated then exit;
   recd := srvsocket.Receive(@buf[0],filesize);
 end;
 totalrecd := 0;
 while totalrecd < fileSize do
 begin
   Application.ProcessMessages;
   if Application.Terminated then exit;
   try
     recd := srvsocket.Receive(@buf[0],SizeOf(buf));
   except
     recd := 0;
   end;
   if recd <= 0 then
     break
   else
   begin
     ms.Write(buf[0],recd);
     totalrecd := totalrecd + recd;
   end;
 end;
 ms.SaveToFile('d:\test\test.mp3');
 srvsocket.Close;
 ms.Free;
 ms2.free;
end;

procedure TForm1.clisocketSessionConnected(Sender: TObject; Error: Word);
begin
     ms2 := TMemoryStream.Create;
     ms2.LoadFromFile('g:\tysk\Lautsprecher - Richtig Laut (Mario Lopez Remix).mp3');
     filesize := ms2.Size;
     CliSocket.Send(ms2.Memory,ms2.Size);
     CliSocket.Close;
end;

end.



Commented:
Hadn't realized you were workin with mp3s!
Well, the best way to reduce mem. consumption would be to
not use memstream.LoadFromFile; instead, read blocks of data from the file and store in a buffer array. check out the BlockRead/BlockWrite functions. Do away with the memory streams and try this:

type
  T16Kb = 0..16383;
  T32Kb = 0..32767;
  T64Kb = 0..65535;
  T128Kb = 0..131071;

procedure TForm1.clisocketSessionConnected(Sender: TObject; Error: Word);
var
  f: file;
  buf: array[T64Kb] of byte;
  bread: integer;
begin
  try
    AssignFile(f,'g:\tysk\Lautsprecher - Richtig Laut (Mario Lopez Remix).mp3');
    Reset(f);
    filesize := System.FileSize(f); //i THINK it's the System unit
    while not EOF(f) do
    begin
      BlockRead(f,buf[0],SizeOf(buf),bread); //pls check my syntax here
      //add any progress bar code here eg. prgbar.position := prgbar.position + Round((bread/filesize)*100)
      CliSocket.Send(@buf[0],bread);
    end;    
    CliSocket.Close;
    CloseFile(f);
  except
    CliSocket.Close;
    MessageDlg('Failed to send file',mtError,[mbOk],0);
  end;
end;

//---------------------------------------

procedure TForm1.clisocketDataAvailable(Sender: TObject; Error: Word);
var
  buf: array [T64Kb] of byte;
  recd, totalrecd, numwrote: integer;
  f: file;
begin
try
  recd := -1;
  while recd <= 0 do
  begin
    Application.ProcessMessages;
    if Application.Terminated then exit;
    recd := srvsocket.Receive(@buf[0],filesize);
  end;
  totalrecd := 0;
  AssignFile(f,'d:\test\test.mp3');
  Rewrite(f);
  while totalrecd < fileSize do
  begin
    Application.ProcessMessages;
    if Application.Terminated then exit;
    try
      recd := srvsocket.Receive(@buf[0],SizeOf(buf));
    except
      recd := 0;
    end;
    if recd <= 0 then
      break
    else
    begin
      BlockWrite(f,buf[0],recd,numwrote); //dbl check this line
      if numwrote < recd then
        raise Exception.Create('Error writing to file')
      else
        totalrecd := totalrecd + recd;
    end;
  end;
  srvsocket.Close;
  CloseFile(f);
except
  on E:Exception do
    MessageDlg(E.Message,mtError,[mbok],0);
  try
    CloseFile(f);
  except
  end;  
end; //try block
end;  //procedure

Author

Commented:
i get IO error 998 on this line :

BlockRead(f,buf[0],SizeOf(buf),bread);

are you sure
 buf: array[T64Kb] of byte;
is the correct?

Author

Commented:
i am not just planning to send mp3's

all sorts of files...

:)

Commented:
Hi Joe,
That T64Kb line's fine - you can replace it with 0..65535 if you prefer.

Try look up I/O Error 998 in the help files. Check that the file exists and there's no sharing violation or anything (like another prog. denying read access (though I doubt this))

rondi

Author

Commented:
rondi, i cannot find out how to handle this error code :-(

Author

Commented:
I Allmost got this one working, but never got the files 100%, i will try testing more in the future :=

Explore More ContentExplore courses, solutions, and other research materials related to this topic.