我使用此代码将文件发送给客户端。
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;
这就像魅力一样,但如果客户端在文件发送时断开连接,Indy会立即终止执行线程,因此文件句柄仍然打开!有没有办法在客户端断开连接后关闭文件句柄?
感谢您的帮助。
答案 0 :(得分:6)
您的代码中有三个问题:
1)直接访问TMemo不是线程安全的,因此可能导致死锁和/或崩溃。 UI访问必须仅在主线程的上下文中完成。您可以使用Indy的TIdSync
或TIdNotify
类从服务器事件安全地访问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;
或者,您可以将文件名传递给Indy并让它为您管理文件:
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;