简体   繁体   English

在Delphi中发送和接收文件

[英]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. 嗨,我正在研究有关如何发送和接收文件的套接字,我正在使用ServerSocket1组件来执行此操作,我在搜索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? 有参考如何使用indy插槽?

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;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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