1

こんにちは、ファイルを送受信する方法についてソケットを研究しています。コンポーネント ServerSocket1 を使用してこれを行っています。Google で検索した次のコードがあります。クライアント

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.

このコードの問題は、他のファイルを再送信しようとすると、「アドレスでのアクセス違反」または「ストリーム読み取りエラー」としてスローされるため、ファイルを送信できるファイルのみを送信できることです。

このコードを修正するために私ができることと、それぞれの後に複数のファイルを送信できますか?

インディソケットでそれを行う方法の参照はありますか?

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 に答える