2012-08-10 48 views
1

我使用此代碼向客戶端發送文件。Indy發送文件並關閉打開的句柄

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); 
var 
hFile : THandle; 
FileBuff : array [0..1023] of byte; 
dwRead : DWORD; 
Recieved : String; 
begin 
Recieved := Athread.Connection.ReadLn; 
if Recieved = 'FILE' then begin 
    Memo1.Lines.Add('Sending File...'); 
    hFile := CreateFileW('FILE.bin', 
    GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); 
    if hFile = INVALID_HANDLE_VALUE then exit; 
    SetFilePointer(hFile, 0, nil, FILE_BEGIN); 
    while true do begin 
    ReadFile(hFile, FileBuff[0], 1024, dwRead, nil); 
    if dwRead <= 0 then break; 
    Athread.Connection.WriteBuffer(FileBuff[0], dwRead); 
    end; 
    CloseHandle (hFile); 
    Athread.Connection.Disconnect; 
end; 
end; 

這就像一個魅力,但如果客戶端斷開連接,而該文件被髮送,印地終止立即執行線程,這樣的文件句柄仍然是開放的!客戶端斷開連接後有沒有辦法關閉文件句柄?

謝謝你的幫助。

+4

您嘗試使用'try..finally..end '? – RRUZ 2012-08-11 00:43:42

回答

6

你的代碼中有三個問題:

1)直接訪問TMemo不是線程安全的,因此它可能導致死鎖和/或崩潰。 UI訪問只能在主線程的上下文中完成。您可以使用Indy的TIdSyncTIdNotify類從服務器事件安全地訪問UI。 2)像提到的RRUZ一樣,你不能保護文件句柄免受異常。如果引發異常,例如客戶端斷開連接,則不會關閉文件句柄。

3)您正在使用相對路徑打開文件。始終使用絕對路徑來確保使用正確的文件。

試試這個:

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); 
var 
hFile : THandle; 
FileBuff : array [0..1023] of byte; 
dwRead : DWORD; 
Recieved : String; 
begin 
    Recieved := Athread.Connection.ReadLn; 
    if Recieved = 'FILE' then begin 
    // I'll leave this as an exercise for you to figure out... 
    //Memo1.Lines.Add('Sending File...'); 

    hFile := CreateFile('C:\Path\FILE.bin', GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0); 
    if hFile = INVALID_HANDLE_VALUE then RaiseLastOSError; 
    try 
     repeat 
     if not ReadFile(hFile, FileBuff[0], SizeOf(FileBuff), dwRead, nil) then RaiseLastOSError; 
     if dwRead = 0 then Break; 
     AThread.Connection.WriteBuffer(FileBuff[0], dwRead); 
     until False; 
    finally 
     CloseHandle(hFile); 
    end; 
    AThread.Connection.Disconnect; 
    end; 
end; 

或者,你可以將文件名傳遞給印,讓它爲您管理文件:

procedure TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); 
var 
Recieved : String; 
begin 
    Recieved := Athread.Connection.ReadLn; 
    if Recieved = 'FILE' then begin 
    // I'll leave this as an exercise for you to figure out... 
    //Memo1.Lines.Add('Sending File...'); 

    AThread.Connection.WriteFile('C:\Path\FILE.bin', True); 
    AThread.Connection.Disconnect; 
    end; 
end; 
+0

看起來不錯!非常感謝你。我只是不知道,除非在那種情況下實際上會被調用。 – 2012-08-11 03:41:27

相關問題