簡體   English   中英

在Delphi 2010中使用套接字發送文件

[英]Send files using sockets in Delphi 2010

嗨,我正在通過tsocket發送文件,我正在編輯第一個代碼以不使用opendilalog,但我想使用一個字符串來發送文件的路徑,問題是OpenDialog編輯的第二個代碼未使用向我射擊錯誤,指出要發送的文件正在被另一個進程使用。

第一個來源

procedure TForm1.Button2Click(Sender: TObject);
begin
   if ClientSocket1.Active = True then
   begin
      OpenDialog1.Filter := 'All Files (*.*)';  // you can add more choices by adding | and followed by description and (*.extension)
      OpenDialog1.FilterIndex := 1; // Here you follow which index number from above you want
      if OpenDialog1.Execute then
      begin
         Edit1.Text := ExtractFileName(OpenDialog1.FileName); // To send as filename after
         ClientSocket1.Socket.SendText('FILE!'+Edit1.Text);
         sleep(2000); // Need to sleep so the other end has time to process the commands
         Streamsize := TFileStream.Create(OpenDialog1.FileName, fmopenread); // Stream created just to Calculate size
         Edit2.Text := inttostr(Streamsize.Size);
         Sleep(2000);
         ClientSocket1.Socket.SendText('SIZE!'+Edit2.Text); // Sends filesize through primary socket
         Streamsize.Position := 0;
         Streamsize.Free;
         sleep(2000);
         ClientSocket2.Address := Edit3.Text;
         ClientSocket2.Open; // ready to send file on second socket
         if ClientSocket2.Socket.SendStream(TFileStream.Create(OpenDialog1.FileName, fmopenRead)) then memo1.Lines.Add('File Sent');
      // above creates a stream and sends as a stream its in a if line because this is the only way it will automatically check the byte order and send the whole stream
      end;
   end
     else
     MessageDlg('Error: You are not connected', mtError, [MbOK],0);  // Error Check above code won't work until the socket is connected
end;

第二個來源

procedure TForm1.Button2Click(Sender: TObject);
var
  archivo: string;
begin
  archivo := 'c:/clap.jpg';
  if ClientSocket1.Active = True then
  begin

    Edit1.Text := ExtractFileName(archivo);
    // To send as filename after
    ClientSocket1.Socket.SendText('FILE!' + Edit1.Text);
    sleep(2000); // Need to sleep so the other end has time to process the commands
    Streamsize := TFileStream.Create(archivo, fmopenread);
    // Stream created just to Calculate size
    Edit2.Text := inttostr(Streamsize.Size);
    sleep(2000);
    ClientSocket1.Socket.SendText('SIZE!' + Edit2.Text);
    // Sends filesize through primary socket
    Streamsize.Position := 0;
    Streamsize.Free;
    sleep(2000);
    ClientSocket2.Address := '127.0.0.1';
    ClientSocket2.Open; // ready to send file on second socket
    if ClientSocket2.Socket.SendStream(TFileStream.Create(archivo, fmopenread))
      then
      Memo1.Lines.Add('File Sent');
    // above creates a stream and sends as a stream its in a if line because this is the only way it will automatically check the byte order and send the whole stream
  end
  else
    MessageDlg('Error: You are not connected', mtError, [MbOK], 0); // Error Check above code won't work until the socket is connected
end;

服務器。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ScktComp, ComCtrls, idglobal, ExtCtrls, ShellAPI;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Label1: TLabel;
    ServerSocket1: TServerSocket;
    ServerSocket2: TServerSocket;
    GroupBox1: TGroupBox;
    Edit1: TEdit;
    Edit2: TEdit;
    Label2: TLabel;
    Label3: TLabel;
    ProgressBar1: TProgressBar;
    Timer1: TTimer;
    StatusBar1: TStatusBar;
    procedure Button1Click(Sender: TObject);
    procedure ServerSocket1Accept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket2Accept(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket1ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure ServerSocket2ClientRead(Sender: TObject;
      Socket: TCustomWinSocket);
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private declarations }
    IncommingStream: TFileStream;
    TimeTaken: integer;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

// Written by me ColdFuzion
// All i ask is i be given some credit for coding this my e-mail is ColdFuzion@hushmail.com
// Program Usage: To recieve Files sent by the client

procedure TForm1.Button1Click(Sender: TObject);
begin
   ServerSocket1.Open;
   Memo1.Lines.Add('Server Listening on '+inttostr(ServerSocket1.Port) );
end;

procedure TForm1.ServerSocket1Accept(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   Memo1.Lines.Add('Client connected From '+Socket.RemoteHost)
   // Adds the clients host as it connects
end;

procedure TForm1.ServerSocket2Accept(Sender: TObject;
  Socket: TCustomWinSocket);
begin
   Memo1.Lines.Add('Incoming File Transfer');
end;

procedure TForm1.ServerSocket1ClientRead(Sender: TObject;
  Socket: TCustomWinSocket);
var IncommingText, StrippedData, CommandName: string;
begin
     IncommingText := socket.ReceiveText;
     StrippedData := copy(IncommingText,6,length(IncommingText) );
     CommandName := copy(IncommingText,0,5);
     if CommandName = 'FILE!' then
     begin
        IncommingStream := TFileStream.Create(StrippedData, fmCREATE or fmOPENWRITE and fmsharedenywrite); // Once File name is recieved the stream to recieve
        Edit1.Text := StrippedData;                                                                        // The file is created
        ServerSocket2.Open;
     end
     else
     if CommandName = 'SIZE!' then
     begin
        Edit2.Text := StrippedData;
        ProgressBar1.Max := StrToInt(StrippedData);
        ProgressBar1.Min := 0;
        Memo1.lines.Add('Recieving File '+Edit1.Text +' of size '+Edit2.Text);
     end;
end;

procedure TForm1.ServerSocket2ClientRead(Sender: TObject;
 // This is the secondary socket it is the most important part of the program
  Socket: TCustomWinSocket);
  // It processes the incomming file stream
var Buffer: array [0..9999] of Char;
    IncommingLen, RecievedLen: integer;
    Filepath: string;
begin
   Timer1.Enabled := True;
   IncommingLen := socket.ReceiveLength;
   // If the size of any incomming data is the size of 0 then the process begins
    Filepath := ExtractFilePath(Edit1.Text)+Edit1.Text;
    // Sets a String Filepath for the actual directory with the filename so that the shellexecute can run this after
    while IncommingLen > 0 do
    // Must make sure the process ends

    begin
       RecievedLen := socket.ReceiveBuf(Buffer, Sizeof(Buffer));
       // Changes the size of RecievedLen by the amount of incoming data recieved
    if RecievedLen <= 0 then
    // Small part of the code where once the buffer reaches 0 the code will exit
       Break
    else
    IncommingStream.Write(Buffer, RecievedLen);
    // Writes the Incoming data into a new stream by the filename and size which is recieved
    ProgressBar1.StepBy(RecievedLen);
    // through the primary socket Also this line increases the progess indicator bar
    if IncommingStream.Size >= strtoint(Edit2.Text) then
    // Onces the stream size begins to reach the size which was sent before sending the file then this
    begin
     // procedure will start
       IncommingStream.Free;
        // Free's the stream
       memo1.Lines.Add('File '+Edit1.Text +' Recieved Successfuly');
       memo1.Lines.Add('Time Taken to Recieve File ' +IntToStr(TimeTaken)+' seconds');
       ServerSocket1.Socket.Connections[0].SendText('DONE!');
       Edit1.Text := '';
       // From here it starts setting the variables back
       Edit2.Text := '';
       ProgressBar1.Position := 0;
       Timer1.Enabled := False;
       TimeTaken := 0;
       if Messagedlg('Would you Like to open the recieved file?', mtConfirmation, [MbYes,MbNo],0) = MrYes then   // Simply asks the user if he wants to open the file if yes will execute if no break
       begin
       ShellExecute(Form1.Handle, 'open', pchar(Filepath),nil, nil, SW_NORMAL);  // A shellapi was added to uses to beable to execute this line
       end;
       Break;                                                                         // This line basically executes any file using the extension from the windows ini files.
    end;
    end;
    end;


procedure TForm1.FormCreate(Sender: TObject);
begin
   Memo1.Text := '';
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
inc(TimeTaken,1);
// Counts number of seconds starts once the filestream begins
end;

end.

// This entire Program could use alot more Error checking but it simply is a very basic
// Example of how to do certain things using the basic components that come with Delphi
// There are hardly any examples of sending files with delphi on the internet so most of
// the code here had to be improvised i hope this helps people where i had to struggle with

我可以更正為第二個代碼以消除更多錯誤嗎?

如果操作系統抱怨該文件已在使用中,則說明它實際上已在使用中。

您正在創建到同一個文件的多個流(也使用了錯誤的路徑分隔符)。 創建一個流並重復使用多次,例如:

procedure TForm1.Button2Click(Sender: TObject);
var
  archivo: string;
  Strm: TFileStream;
begin
  archivo := 'c:\clap.jpg';
  if ClientSocket1.Active then
  begin
    Strm := TFileStream.Create(archivo, fmOpenRead or fmShareDenyWrite);
    try
      Edit1.Text := ExtractFileName(archivo);
      Edit2.Text := IntToStr(Strm.Size);
      ClientSocket1.Socket.SendText('FILE!' + Edit1.Text);
      // Need to sleep so the other end has time to process the commands
      Sleep(2000);
      ClientSocket1.Socket.SendText('SIZE!' + Edit2.Text);
      Sleep(2000);
      ClientSocket2.Address := '127.0.0.1';
      ClientSocket2.Open; // ready to send file on second socket
      if ClientSocket2.Socket.SendStream(Strm) then
      begin
        // SendStream() takes ownership of the Stream, so don't free it!
        Strm := nil;
        Memo1.Lines.Add('File Sent');
      end;
    finally
      Strm.Free;
    end;
  end
  else
    MessageDlg('Error: You are not connected', mtError, [MbOK], 0);
end;

如前所述,SendStream()獲得流的所有權。 如果您在非阻塞模式下使用套接字,則可能需要花費一些時間來傳輸整個流。 在傳輸完成之前,您將無法再次重新打開文件。 那可以解釋您所看到的錯誤。

如此說來,您必須在協議中引入休眠機制以正確處理命令這一事實意味着您在開始時就沒有很好地設計協議。 在命令之間放置定界符會更加可靠,例如:

procedure TForm1.Button2Click(Sender: TObject);
var
  archivo: string;
  Strm: TFileStream;
begin
  archivo := 'c:\clap.jpg';
  if ClientSocket1.Active then
  begin
    Strm := TFileStream.Create(archivo, fmOpenRead or fmShareDenyWrite);
    try
      Edit1.Text := ExtractFileName(archivo);
      Edit2.Text := IntToStr(Strm.Size);
      ClientSocket1.Socket.SendText('FILE!' + Edit1.Text + #13#10);
      ClientSocket1.Socket.SendText('SIZE!' + Edit2.Text + #13#10);
      ClientSocket2.Address := '127.0.0.1';
      ClientSocket2.Open; // ready to send file on second socket
      if ClientSocket2.Socket.SendStream(Strm) then
      begin
        // SendStream() takes ownership of the Stream and will free it
        // after it is done sending, so don't free it yourself!
        Strm := nil;
        Memo1.Lines.Add('File Sent');
      end;
    finally
      Strm.Free;
    end;
  end
  else
    MessageDlg('Error: You are not connected', mtError, [MbOK], 0);
end;

然后,接收器可以簡單地讀取入站數據,並根據需要在定界符上對其進行拆分,而無需進行睡眠。

順便說一句,您實際上是在使用不同的語法重新創建FTP協議 ,所以為什么不使用實際的FTP協議呢? 有許多FTP組件/庫可供使用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM