简体   繁体   中英

Send & receive files in Delphi

Hi I'm studying sockets on how to send and receive files, I'm using the component ServerSocket1 to do this I have the following code I found searching google. the client

unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    ClientSocket1: TClientSocket;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure ClientSocket1Connect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ClientSocket1Error(Sender: TObject; Socket: TCustomWinSocket;
      ErrorEvent: TErrorEvent; var ErrorCode: Integer);
    procedure Button2Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ClientSocket1Read(Sender: TObject; Socket: TCustomWinSocket);
  private
    { Private declarations }
    Stream: TMemoryStream;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
begin
  ClientSocket1.Address:= '127.0.0.1';
  ClientSocket1.Port:= 2500;
  ClientSocket1.Open;
end;

procedure TForm1.ClientSocket1Connect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  ShowMessage('Connected.. Now go load a file!');
end;

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


procedure TForm1.Button2Click(Sender: TObject);
var
  Size: Integer;
begin
  if OpenDialog1.Execute Then
  begin
    Stream.LoadFromFile(OpenDialog1.Filename);
    Size:= Stream.Size;
    ClientSocket1.Socket.SendBuf(Size,SizeOf(Size));
    ClientSocket1.Socket.SendStream(Stream);
  End;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  Stream:= TMemoryStream.Create;
end;

procedure TForm1.ClientSocket1Read(Sender: TObject;
  Socket: TCustomWinSocket);
var
  S: String;
begin
  S:= Socket.ReceiveText;
  Socket.Close;
  ShowMessage('Client: '+S);
end;

end.

the server

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ScktComp;

type
  TForm1 = class(TForm)
    ServerSocket1: TServerSocket;
    SaveDialog1: TSaveDialog;
    procedure FormCreate(Sender: TObject);
    procedure ServerSocket1ClientConnect(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1Listen(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
  private
    { Private declarations }
    Stream: TMemoryStream;
    FSize: Integer;
    writing: Boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  ServerSocket1.Port:= 2500;
  ServerSocket1.Active:= True;
  Stream:= TMemoryStream.Create;
  writing:= False;
end;

procedure TForm1.ServerSocket1ClientConnect(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  ShowMessage('A client has connected');
end;

procedure TForm1.ServerSocket1Listen(Sender: TObject;
  Socket: TCustomWinSocket);
begin
  ShowMessage('I''m listening');
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var
  BytesReceived: Longint;
  CopyBuffer: Pointer; { buffer for copying }
  ChunkSize: Integer;
  TempSize: Integer;
const
  MaxChunkSize: Longint = 8192; { copy in 8K chunks }
begin
  If FSize=0 then
  begin
    If Socket.ReceiveLength>SizeOf(TempSize) then
    begin
      Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
      Stream.SetSize(TempSize);
      FSize:= TempSize //Threadsafe code!
    End;
  End;
  If (FSize>0) and not(writing) then
  begin
    GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
    writing:= True;
    While Socket.ReceiveLength>0 do
    Begin
      ChunkSize:= Socket.ReceiveLength;
      If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
      BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
      Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
      Dec(FSize,BytesReceived);
    End;
    If FSize=0 then
    If SaveDialog1.Execute then
    begin
      If FileExists(SaveDialog1.Filename) then
        DeleteFile(SaveDialog1.Filename);
      Stream.SaveToFile(SaveDialog1.Filename);
      Socket.SendText('File received!');
      Stream.SetSize(0);
      FSize:= 0;
    End;
    FreeMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
    Writing:= False;
  End;
end;


end.

The problem in this code that eh had is that I can only send one I can send a file because when I try to re-send other file errors throws me as 'Access violation at address' or 'Stream read error'.

that I can do to fix this code and you can send multiple files after each?

there is a reference of how to do it with indy sockets?

This is because memorystream used to open the file is not free. You have to free the stream variable before loading the next file to be sent.

I modified your code a bit and it is now working perfectly, I request various files and is ok.

the server



    procedure TForm1.ServerClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    var
      BytesReceived: Longint;
      CopyBuffer: Pointer; { buffer for copying }
      ChunkSize: Integer;
      TempSize: Integer;
      FileName: array [0..255] of char;
    const
      MaxChunkSize: Longint = 8192; { copy in 8K chunks }
    begin
      If FSize=0 then
      begin
        If Socket.ReceiveLength>SizeOf(TempSize) then
        begin
          Socket.ReceiveBuf(TempSize,SizeOf(TempSize));
          Socket.ReceiveBuf(FileName, sizeOf(FileName));
          Save.FileName:= FileName; //I added
          Stream:= TMemoryStream.Create;
          Stream.SetSize(TempSize);
          FSize:= TempSize; //Threadsafe code!
          writing:= True;
        End;
      End;
      If (FSize>0) and (writing) then
{before not(writing) -> because in big files, ServerClientRead is call more than one time and the transfer was stopped after the first call, but now it continues.}
      begin
        GetMem(CopyBuffer, MaxChunkSize); { allocate the buffer }
        While Socket.ReceiveLength>0 do
        Begin
          ChunkSize:= Socket.ReceiveLength;
          If ChunkSize > MaxChunkSize then ChunkSize:= MaxChunkSize;
          BytesReceived:= Socket.ReceiveBuf(CopyBuffer^,ChunkSize);
          Stream.Write(CopyBuffer^, BytesReceived); { ...write chunk }
          Dec(FSize,BytesReceived);
        End;
        FreeMem(CopyBuffer, MaxChunkSize); { free allocated buffer, now here }
        If FSize

Client button click:



    procedure TForm1.Button1Click(Sender: TObject);
    var ms: TMemoryStream;
        size: Integer;
        FileName: array [0..255] of char;
    begin
      if Open.Execute then
      begin
        ms:= TMemoryStream.Create;
        try
          ms.LoadFromFile(open.FileName);
          ms.Position:= 0;
          Size:= MS.Size;
          Client.Socket.SendBuf(Size,SizeOf(Size));
          StrPLCopy(FileName, ExtractFileName(Open.FileName), High(FileName));
          Client.Socket.SendBuf(FileName, SizeOf(FileName));
          client.Socket.SendStream(ms);
        except
          ms.Free;
        end;
      end;
    end;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM