1

嗨,我正在研究如何发送和接收文件的套接字,我正在使用组件 ServerSocket1 来执行此操作我有以下代码,我在谷歌上找到了以下代码。客户端

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.

服务器

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.

这个代码中的问题是我只能发送一个我可以发送一个文件,因为当我尝试重新发送其他文件时,错误会将我抛出为“地址访问冲突”或“流读取错误”。

我可以做些什么来修复此代码,并且您可以在每个文件之后发送多个文件?

有关于如何使用 indy 套接字的参考?

4

2 回答 2

1

这是因为用于打开文件的内存流不是空闲的。在加载下一个要发送的文件之前,您必须释放流变量。

于 2014-03-12T06:15:23.447 回答
0

我稍微修改了您的代码,现在它运行良好,我请求了各种文件并且没问题。

服务器



    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;

于 2014-10-07T22:54:19.720 回答