2013-10-13 122 views
1

您好我正在學習如何發送和接收文件的套接字,我正在使用組件ServerSocket1來做到這一點我有以下代碼,我發現搜索谷歌。 客戶在Delphi中發送和接收文件

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套接字的參考?

+1

避免使用'ScktComp' - 這是非常過時了。它現在只存在向後兼容性。 –

+0

另外,什麼版本的德爾福? –

+0

我使用德爾福2010 –

回答

1

這是因爲用於打開文件的內存流不是免費的。您必須在加載下一個要發送的文件之前釋放流變量。

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按鈕點擊:

 

    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;