根据客户端请求通过 IdTCPServer 发送文件
Send file via IdTCPServer upon request of client
如果执行客户端请求,我正在尝试通过 TCP 服务器发送文本文件。互联网上的例子已经过时或没有用。我知道我应该使用流,但我不知道该怎么做。
我改编了我在互联网上找到的代码,但我对流感到困惑。有人可以指导我正确的方向吗?
服务器:
TForm2.bStartClick(Sender: TObject);
begin
if not IdTCPServer1.Active then
begin
IdTCPServer1.Active := True;
Log('Server started on port ' + IntToStr(IdTCPServer1.DefaultPort));
bStart.Enabled := False;
bStop.Enabled := True;
end;
end;
procedure TForm2.bStopClick(Sender: TObject);
begin
if IdTCPServer1.Active then
begin
IdTCPServer1.Active := False;
Log('Server stopped');
bStop.Enabled := False;
bStart.Enabled := True;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
bStart.Enabled := True;
bStop.Enabled := False;
end;
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
s: string; FS:TFileStream;
begin
if s ='1' then
begin
FS := TFileStream.Create(MyPath, fmOpenShare);
try
AContext.Connection.WriteStream(FS);
finally
FS.Free;
end;
end;
end;
procedure TForm2.Log(const s: string);
begin
mLog.Lines.Add(s);
end
客户:
procedure TForm1.bConnectClick(Sender: TObject);
begin
IdTCPClient1.Host := eServer.Text;
IdTCPClient1.Port := StrToInt(ePort.Text);
IdTCPClient1.Connect;
if IdTCPClient1.Connected then
begin
Log('Connected to ' + IdTCPClient1.Host + ':' +
IntToStr(IdTCPClient1.Port));
bConnect.Enabled := False;
bDisconnect.Enabled := True;
bSend.Enabled := True;
end;
end;
procedure TForm1.bDisconnectClick(Sender: TObject);
begin
IdTCPClient1.Disconnect;
bDisconnect.Enabled := False;
bConnect.Enabled := True;
bSend.Enabled := False;
end;
procedure TForm1.bSendClick(Sender: TObject);
var
FS: TFileStream;
begin
// IdTCPClient1.IOHandler.WriteLn(eTextToSend.Text);
FS := TFileStream.Create('C:\Users\xxx\Desktop\test.txt', fmCreate);
try
IdTCPClient1.ReadStream(FS);
finally
Fs.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
bDisconnect.Enabled := False;
bSend.Enabled := False;
end;
procedure TForm1.Log(const s: string);
begin
mLog.Lines.Add(s);
end;
您的客户端没有向服务器发送任何命令,服务器在发送文件之前也没有等待任何命令。
但是,除此之外,您的代码无论如何都无法编译,因为 TIdTCPConnection
没有 WriteStream()
和 ReadStream()
方法。正确的方法是 TIdIOHandler.Write(TStream)
和 TIdIOHandler.ReadStream()
.
但即便如此,您对写入流和读取流的调用也不匹配,因为 Write(TStream)
默认情况下不会将流大小发送到对等方,但 ReadStream()
确实希望收到默认情况下的流大小。
尝试更像这样的东西:
服务器:
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
s: string;
FS: TFileStream;
begin
s := AContext.Connection.IOHandler.ReadLn;
if s = 'SENDFILE' then
begin
try
FS := TFileStream.Create(MyPath, fmOpenRead or fmShareDenyWrite);
except
AContext.Connection.IOHandler.WriteLn('500 Cannot open file');
Exit;
end;
try
AContext.Connection.IOHandler.WriteLn('200 Sending file');
AContext.Connection.IOHandler.LargeStream := True;
AContext.Connection.IOHandler.Write(FS, 0, True);
finally
FS.Free;
end;
end
else
AContext.Connection.IOHandler.WriteLn('500 Unknown command');
end;
客户:
procedure TForm1.bSendClick(Sender: TObject);
var
FS: TFileStream;
begin
FS := TFileStream.Create('C:\Users\xxx\Desktop\test.txt', fmCreate);
try
try
IdTCPClient1.IOHandler.SendCmd('SENDFILE', 200);
IdTCPClient1.IOHandler.LargeStream := True;
IdTCPClient1.IOHandler.ReadStream(FS, -1, False);
finally
FS.Free;
end;
except
DeleteFile('C:\Users\xxx\Desktop\test.txt');
raise;
end;
end;
在这种情况下,您可以考虑使用 TIdCmdTCPServer
,然后您可以使用它的 CommandHandlers
集合在设计时直观地定义您的命令,并分配 OnCommand
事件处理程序在运行时处理它们,例如:
// OnCommand handler for 'SENDFILE' command
procedure TForm2.IdCmdTCPServer1SENDFILECommand(ASender: TIdCommand);
var
FS: TFileStream;
begin
try
FS := TFileStream.Create(MyPath, fmOpenRead or fmShareDenyWrite);
except
ASender.SetReply(500, 'Cannot open file');
Exit;
end;
try
ASender.SetReply(200, 'Sending file');
ASender.SendReply;
AContext.Connection.IOHandler.LargeStream := True;
AContext.Connection.IOHandler.Write(FS, 0, True);
finally
FS.Free;
end;
end;
如果执行客户端请求,我正在尝试通过 TCP 服务器发送文本文件。互联网上的例子已经过时或没有用。我知道我应该使用流,但我不知道该怎么做。
我改编了我在互联网上找到的代码,但我对流感到困惑。有人可以指导我正确的方向吗?
服务器:
TForm2.bStartClick(Sender: TObject);
begin
if not IdTCPServer1.Active then
begin
IdTCPServer1.Active := True;
Log('Server started on port ' + IntToStr(IdTCPServer1.DefaultPort));
bStart.Enabled := False;
bStop.Enabled := True;
end;
end;
procedure TForm2.bStopClick(Sender: TObject);
begin
if IdTCPServer1.Active then
begin
IdTCPServer1.Active := False;
Log('Server stopped');
bStop.Enabled := False;
bStart.Enabled := True;
end;
end;
procedure TForm2.FormCreate(Sender: TObject);
begin
bStart.Enabled := True;
bStop.Enabled := False;
end;
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
s: string; FS:TFileStream;
begin
if s ='1' then
begin
FS := TFileStream.Create(MyPath, fmOpenShare);
try
AContext.Connection.WriteStream(FS);
finally
FS.Free;
end;
end;
end;
procedure TForm2.Log(const s: string);
begin
mLog.Lines.Add(s);
end
客户:
procedure TForm1.bConnectClick(Sender: TObject);
begin
IdTCPClient1.Host := eServer.Text;
IdTCPClient1.Port := StrToInt(ePort.Text);
IdTCPClient1.Connect;
if IdTCPClient1.Connected then
begin
Log('Connected to ' + IdTCPClient1.Host + ':' +
IntToStr(IdTCPClient1.Port));
bConnect.Enabled := False;
bDisconnect.Enabled := True;
bSend.Enabled := True;
end;
end;
procedure TForm1.bDisconnectClick(Sender: TObject);
begin
IdTCPClient1.Disconnect;
bDisconnect.Enabled := False;
bConnect.Enabled := True;
bSend.Enabled := False;
end;
procedure TForm1.bSendClick(Sender: TObject);
var
FS: TFileStream;
begin
// IdTCPClient1.IOHandler.WriteLn(eTextToSend.Text);
FS := TFileStream.Create('C:\Users\xxx\Desktop\test.txt', fmCreate);
try
IdTCPClient1.ReadStream(FS);
finally
Fs.Free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
bDisconnect.Enabled := False;
bSend.Enabled := False;
end;
procedure TForm1.Log(const s: string);
begin
mLog.Lines.Add(s);
end;
您的客户端没有向服务器发送任何命令,服务器在发送文件之前也没有等待任何命令。
但是,除此之外,您的代码无论如何都无法编译,因为 TIdTCPConnection
没有 WriteStream()
和 ReadStream()
方法。正确的方法是 TIdIOHandler.Write(TStream)
和 TIdIOHandler.ReadStream()
.
但即便如此,您对写入流和读取流的调用也不匹配,因为 Write(TStream)
默认情况下不会将流大小发送到对等方,但 ReadStream()
确实希望收到默认情况下的流大小。
尝试更像这样的东西:
服务器:
procedure TForm2.IdTCPServer1Execute(AContext: TIdContext);
var
s: string;
FS: TFileStream;
begin
s := AContext.Connection.IOHandler.ReadLn;
if s = 'SENDFILE' then
begin
try
FS := TFileStream.Create(MyPath, fmOpenRead or fmShareDenyWrite);
except
AContext.Connection.IOHandler.WriteLn('500 Cannot open file');
Exit;
end;
try
AContext.Connection.IOHandler.WriteLn('200 Sending file');
AContext.Connection.IOHandler.LargeStream := True;
AContext.Connection.IOHandler.Write(FS, 0, True);
finally
FS.Free;
end;
end
else
AContext.Connection.IOHandler.WriteLn('500 Unknown command');
end;
客户:
procedure TForm1.bSendClick(Sender: TObject);
var
FS: TFileStream;
begin
FS := TFileStream.Create('C:\Users\xxx\Desktop\test.txt', fmCreate);
try
try
IdTCPClient1.IOHandler.SendCmd('SENDFILE', 200);
IdTCPClient1.IOHandler.LargeStream := True;
IdTCPClient1.IOHandler.ReadStream(FS, -1, False);
finally
FS.Free;
end;
except
DeleteFile('C:\Users\xxx\Desktop\test.txt');
raise;
end;
end;
在这种情况下,您可以考虑使用 TIdCmdTCPServer
,然后您可以使用它的 CommandHandlers
集合在设计时直观地定义您的命令,并分配 OnCommand
事件处理程序在运行时处理它们,例如:
// OnCommand handler for 'SENDFILE' command
procedure TForm2.IdCmdTCPServer1SENDFILECommand(ASender: TIdCommand);
var
FS: TFileStream;
begin
try
FS := TFileStream.Create(MyPath, fmOpenRead or fmShareDenyWrite);
except
ASender.SetReply(500, 'Cannot open file');
Exit;
end;
try
ASender.SetReply(200, 'Sending file');
ASender.SendReply;
AContext.Connection.IOHandler.LargeStream := True;
AContext.Connection.IOHandler.Write(FS, 0, True);
finally
FS.Free;
end;
end;