简体   繁体   English

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

[英]Send files using sockets in Delphi 2010

Hi I am sending a file via tsocket, I'm editing the first code to not use opendilalog but I want to use a string with the path of the file to send, the problem is that the second code that eh OpenDialog edited for not using shoot me an error saying the file to send is being used by another process. 嗨,我正在通过tsocket发送文件,我正在编辑第一个代码以不使用opendilalog,但我想使用一个字符串来发送文件的路径,问题是OpenDialog编辑的第二个代码未使用向我射击错误,指出要发送的文件正在被另一个进程使用。

The first source 第一个来源

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;

The second source 第二个来源

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;

The server. 服务器。

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

I can correct as the second code to pull no more errors? 我可以更正为第二个代码以消除更多错误吗?

If the OS is complaining that the file is already in use, then it really is already in use. 如果操作系统抱怨该文件已在使用中,则说明它实际上已在使用中。

You are creating multiple streams to the same file (you are also using the wrong path delimiter). 您正在创建到同一个文件的多个流(也使用了错误的路径分隔符)。 Create one stream and reuse it multiple times instead, eg: 创建一个流并重复使用多次,例如:

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;

As noted, SendStream() takes ownership of the stream. 如前所述,SendStream()获得流的所有权。 If you are using the socket in non-blocking mode, it may take time to transfer the whole stream. 如果您在非阻塞模式下使用套接字,则可能需要花费一些时间来传输整个流。 You would not be able to re-open the file again until that transfer is finished. 在传输完成之前,您将无法再次重新打开文件。 That could account for the error you are seeing. 那可以解释您所看到的错误。

Now, with that said, the fact that you have to introduce sleeps into your protocol in order to get commands processed correctly means you did not design your protocol very well to begin with. 如此说来,您必须在协议中引入休眠机制以正确处理命令这一事实意味着您在开始时就没有很好地设计协议。 It would be much more reliable to put a delimiter between your commands instead, eg: 在命令之间放置定界符会更加可靠,例如:

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;

Then the receiver can simply read inbound data and split it on the delimiters as needed, no sleeps needed. 然后,接收器可以简单地读取入站数据,并根据需要在定界符上对其进行拆分,而无需进行睡眠。

BTW, you are essentially recreating the FTP protocol , jut with a different syntax, so why not use the actual FTP protocol instead? 顺便说一句,您实际上是在使用不同的语法重新创建FTP协议 ,所以为什么不使用实际的FTP协议呢? There are plenty of FTP components/libraries readily available. 有许多FTP组件/库可供使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM