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

时间:2013-10-14 20:39:15

标签: delphi

您好我通过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

我可以更正第二个代码来解决错误吗?

1 个答案:

答案 0 :(得分:0)

如果操作系统抱怨该文件已被使用,那么它确实已经在使用中。

您正在为同一个文件创建多个流(您也使用了错误的路径分隔符)。创建一个流并重复使用多次,例如:

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 protocol,但是为什么不使用实际的FTP协议呢?有很多FTP组件/库可供使用。