使用 TCPServer 向 TCPClient 请求 Delphi 的流
Use TCPServer to ask TCPClient for a stream with Delphi
我又来了...现在我正在尝试使用流。我的目标是使用 TCPServer 向 TCPClient 请求流并正确接收它。这是我正在尝试但没有成功的方法:
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
SCmd: string;
Client: TClient;
LQueue: TStringList;
WQueue: TStringList;
Stream: TMemoryStream;
begin
Client := TClient(AContext.Data);
// Send Cmd
LQueue := nil;
try
WQueue := Client.QMsg.Lock;
try
if (WQueue.Count > 0) then
begin
LQueue := TStringList.Create;
LQueue.Assign(WQueue);
WQueue.Clear;
end;
finally
Client.QMsg.Unlock;
end;
if (LQueue <> nil) then
begin
SCmd := LQueue[0];
AContext.Connection.IOHandler.Write(SCmd);
end;
finally
LQueue.Free;
end;
// Receive Data
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
if not AContext.Connection.IOHandler.CheckForDataOnSource(100) then Exit;
AContext.Connection.IOHandler.CheckForDisconnect;
end;
if (SCmd = 'sendfile') then
begin
Stream := TMemoryStream.Create;
try
AContext.Connection.IOHandler.ReadStream(Stream, -1);
Stream.Position := 0;
Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
finally
Stream.Free;
end;
end;
end;
在客户端,我创建了一个线程来监听和处理命令。这是代码:
procedure TClientProc.Execute;
begin
TCPClient := TIdTCPClient.Create(nil);
while (not Terminated) do
begin
with TCPClient do
begin
if (Connected) then
try
FCmd := Trim(IOHandler.ReadLn);
if (FCmd <> '') then Synchronize(CommandProc);
except
end else
begin
if (FCnt >= FInt) then
try
ConnectTimeout := 4000;
Port := StrToInt(FPort);
Host := FHost;
Connect;
except
FCnt := 0;
end else
begin
Inc(FCnt);
end;
end;
Sleep(1000);
end;
end;
TCPClient.Disconnect;
TCPClient.Free;
end;
Procedure TClientProc.CommandProc;
var
Stream: TMemoryStream;
begin
if FCmd = 'sendfile' then
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile(ExtractFilePath(Application.ExeName) + 'test.zip');
Stream.Position := 0;
TCPClient.IOHandler.Write(Stream, 0, True);
finally
Stream.Free;
end;
end;
end;
请问我哪里做错了?
顺便说一句,新年快乐!! :)
在服务器端,如果 TClient
的队列中有多个命令,而 OnExecute
有机会检查它,那么您将丢弃除第一个命令之外的所有命令。你需要全部处理它们。
试试像这样的东西:
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
SCmd: string;
Client: TClient;
WQueue: TStringList;
Stream: TMemoryStream;
begin
Client := TClient(AContext.Data);
// Send Cmd
WQueue := Client.QMsg.Lock;
try
if (WQueue.Count > 0) then
begin
SCmd := WQueue[0];
WQueue.Delete(0);
end;
finally
Client.QMsg.Unlock;
end;
if (SCmd = '') then
begin
AContext.Connection.IOHandler.Write(SCmd);
if (SCmd = 'sendfile') then
begin
Stream := TMemoryStream.Create;
try
AContext.Connection.IOHandler.ReadStream(Stream, -1);
Stream.Position := 0;
Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
finally
Stream.Free;
end;
end;
end;
end;
当然,这只有在服务器是唯一发送命令的一方时才有效。如果客户端曾经向服务器发送命令,这将使代码更难管理,并且需要更详细的协议,因为服务器需要能够区分入站数据何时属于命令还是响应。
我又来了...现在我正在尝试使用流。我的目标是使用 TCPServer 向 TCPClient 请求流并正确接收它。这是我正在尝试但没有成功的方法:
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
SCmd: string;
Client: TClient;
LQueue: TStringList;
WQueue: TStringList;
Stream: TMemoryStream;
begin
Client := TClient(AContext.Data);
// Send Cmd
LQueue := nil;
try
WQueue := Client.QMsg.Lock;
try
if (WQueue.Count > 0) then
begin
LQueue := TStringList.Create;
LQueue.Assign(WQueue);
WQueue.Clear;
end;
finally
Client.QMsg.Unlock;
end;
if (LQueue <> nil) then
begin
SCmd := LQueue[0];
AContext.Connection.IOHandler.Write(SCmd);
end;
finally
LQueue.Free;
end;
// Receive Data
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
if not AContext.Connection.IOHandler.CheckForDataOnSource(100) then Exit;
AContext.Connection.IOHandler.CheckForDisconnect;
end;
if (SCmd = 'sendfile') then
begin
Stream := TMemoryStream.Create;
try
AContext.Connection.IOHandler.ReadStream(Stream, -1);
Stream.Position := 0;
Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
finally
Stream.Free;
end;
end;
end;
在客户端,我创建了一个线程来监听和处理命令。这是代码:
procedure TClientProc.Execute;
begin
TCPClient := TIdTCPClient.Create(nil);
while (not Terminated) do
begin
with TCPClient do
begin
if (Connected) then
try
FCmd := Trim(IOHandler.ReadLn);
if (FCmd <> '') then Synchronize(CommandProc);
except
end else
begin
if (FCnt >= FInt) then
try
ConnectTimeout := 4000;
Port := StrToInt(FPort);
Host := FHost;
Connect;
except
FCnt := 0;
end else
begin
Inc(FCnt);
end;
end;
Sleep(1000);
end;
end;
TCPClient.Disconnect;
TCPClient.Free;
end;
Procedure TClientProc.CommandProc;
var
Stream: TMemoryStream;
begin
if FCmd = 'sendfile' then
begin
Stream := TMemoryStream.Create;
try
Stream.LoadFromFile(ExtractFilePath(Application.ExeName) + 'test.zip');
Stream.Position := 0;
TCPClient.IOHandler.Write(Stream, 0, True);
finally
Stream.Free;
end;
end;
end;
请问我哪里做错了?
顺便说一句,新年快乐!! :)
在服务器端,如果 TClient
的队列中有多个命令,而 OnExecute
有机会检查它,那么您将丢弃除第一个命令之外的所有命令。你需要全部处理它们。
试试像这样的东西:
procedure TfrmMain.TCPServerExecute(AContext: TIdContext);
var
SCmd: string;
Client: TClient;
WQueue: TStringList;
Stream: TMemoryStream;
begin
Client := TClient(AContext.Data);
// Send Cmd
WQueue := Client.QMsg.Lock;
try
if (WQueue.Count > 0) then
begin
SCmd := WQueue[0];
WQueue.Delete(0);
end;
finally
Client.QMsg.Unlock;
end;
if (SCmd = '') then
begin
AContext.Connection.IOHandler.Write(SCmd);
if (SCmd = 'sendfile') then
begin
Stream := TMemoryStream.Create;
try
AContext.Connection.IOHandler.ReadStream(Stream, -1);
Stream.Position := 0;
Stream.SaveToFile(ExtractFilePath(Application.ExeName) + 'test.zip');
finally
Stream.Free;
end;
end;
end;
end;
当然,这只有在服务器是唯一发送命令的一方时才有效。如果客户端曾经向服务器发送命令,这将使代码更难管理,并且需要更详细的协议,因为服务器需要能够区分入站数据何时属于命令还是响应。