[英]How to run code in already running thread to safely send/recv data [TidTCPServer]
更新问题仍然存在。
是否可以在已经运行的线程中运行代码? 例如:线程 1 正在运行一些代码 & 我想从线程 1 中的线程 2 运行代码。
我想在 idTCPServer 线程中运行代码以向客户端发送一些数据
编辑:经过研究,我的问题似乎是当接收到或正在接收客户端数据时,另一个线程正在尝试写入该套接字。
编辑:
procedure TMainFrm.UserSRVExecute(AContext: TIdContext);
var
Command : String;
msSize : Int64;
ms : TMemoryStream;
decompressedMS : TMemoryStream;
H : TIdNotify;
begin
// Application.ProcessMessages;
Command := AContext.Connection.Socket.ReadLn;
// messagebox(0,'snd','',$40);
if logb then mainfrm.mconnections.Lines.Add(command + ' - BEGIN');
if Command <> '' then // keepalive
begin
//Application.ProcessMessages;
msSize := AContext.Connection.Socket.ReadInt64;
ms := TMemoryStream.Create;
decompressedMS := TMemoryStream.Create;
try
AContext.Connection.Socket.ReadStream(ms, msSize);
ms.Position := 0;
DecompressStream(MS,decompressedMS);
decompressedMS.Position := 0;
Client_ProcessData(AContext,Command,decompressedMS);
finally
ms.Free;
decompressedMS.Free;
if logb then mainfrm.mconnections.Lines.Add(command + ' - END');
end;
end;
end;
procedure Client_ProcessData(AContext: TIdContext; cmd : String; data : TMemoryStream);
var
Hnd : THandle;
clData : TStringArray;
TmpStr1 : String;
Tmp : String;
TN : TIdNotify;
Sync : TMySync;
I,I2 : Integer;
begin
Hnd := AContext.Connection.Socket.Binding.Handle;
if cmd = 'scr' then // RECEIVE COMMAND TO SEND TO CLIENT TO RECEIVE DATA FROM CLIENT
begin
Tmp := StreamToString(data);
{Sync := TMySync2.Create(True);
try
Sync.cmd := cmd;
Sync.hnd := Hnd;
Sync.tmp := TmpStr1;
Sync.Resume;
finally
//Sync.Free;
end; }
log('>>> CLFROMAS: '+IntToStr(HND)+':::'+cmd+':::');
// SendCMDToSocket(MainFrm.UserSRV,StrToInt(Trim(Tmp)),'scr'+IntToStr(Hnd));
I2 := StrToInt(Trim(Tmp));
for I := 0 to 100 do
if USRVData[i].hnd = I2 then
begin
// cs.Acquire;
USRVData[i].CTX.Connection.Socket.WriteLn('scr'+IntToStr(Hnd)); // PLACED ALL CONTEXTs IN GLOBAL VARIABLE + ALL SOCKET HANDLES. <--- HERE IS THE PROBLEM
// cs.Release;
Break;
end;
// log('>>> CLFROMAS: '+IntToStr(HND)+':::'+cmd+':::'+streamtostring(data));
Exit;
end;
if Copy(cmd,1,Length('scr4u')) = 'scr4u' then // RECEIVE DATA FROM CLIENT TO SEND IT TO ADMIN CLIENT REQUEST ABOVE
begin
if Length(cmd) > Length('scr4u') then
begin
Delete(cmd,1,Length('scr4u'));
Data.Position := 0;
{ Sync := TMySync.Create;
try
Sync.cmd := cmd;
Sync.hnd := Hnd;
Sync.data := TMemoryStream.Create;
Sync.data.CopyFrom(data,data.Size);
Sync.data.Position := 0;
Sync.DoNotify;
finally
Sync.data.Free;
Sync.Free;
end; }
SendStreamToSocket(MainFrm.UserSRV,strtoint(cmd),'scr4u',Data);
log('>>>>> ADMIN: '+IntToStr(HND)+':::'+cmd+':::'{+streamtostring(data)});
end else TmpStr1 := '';
Exit;
end;
...
更新
procedure TMainFrm.UserSRVExecute(AContext: TIdContext);
var
Command : String;
msSize : Int64;
ms : TMemoryStream;
decompressedMS : TMemoryStream;
H : TIdNotify;
I : Integer;
List, Messages : TStringList;
begin
Messages := nil;
try
List := TMyContext(AContext).OutgoingMessages.Lock;
try
if List.Count > 0 then
begin
Messages := TStringList.Create;
Messages.Assign(List);
List.Clear;
end;
finally
TMyContext(AContext).OutgoingMessages.Unlock;
end;
if Messages <> nil then
begin
for I := 0 to Messages.Count-1 do
begin
AContext.Connection.IOHandler.WriteLn(Messages.Strings[I]);
end;
end;
finally
Messages.Free;
end;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
Exit;
end;
Command := AContext.Connection.Socket.ReadLn;
if logb then mainfrm.mconnections.Lines.Add(command + ' - BEGIN');
if Command <> '' then
begin
msSize := AContext.Connection.Socket.ReadInt64;
ms := TMemoryStream.Create;
decompressedMS := TMemoryStream.Create;
try
AContext.Connection.Socket.ReadStream(ms, msSize);
ms.Position := 0;
DecompressStream(MS,decompressedMS);
decompressedMS.Position := 0;
Client_ProcessData(AContext,Command,decompressedMS);
finally
ms.Free;
decompressedMS.Free;
if logb then mainfrm.mconnections.Lines.Add(command + ' - END');
end;
end;
end;
是否可以在已经运行的线程中运行代码? 例如:线程 1 正在运行一些代码 & 我想从线程 1 中的线程 2 运行代码。
不可以。需要对 Thread1 进行显式编码以停止它当前正在执行的操作,执行其他操作,然后返回到它之前执行的操作。 Thread2 所能做的就是通知 Thread1 尽早执行停止+继续。
我想在 idTCPServer 线程中运行代码以向客户端发送一些数据
您的TIdTCPServer.OnExecute
事件处理程序需要定期检查该数据并在可用时发送它。
您可以使用TIdContext.Data
属性,或从TIdServerContext
派生自定义类并将其分配给TIdTCPServer.ContextClass
属性,为您的出站数据提供每个客户端的线程安全缓冲区。 然后,您的OnExecute
处理程序可以在需要时访问该缓冲区。
例如:
type
TMyContext = class(TIdServerContext)
public
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil); override;
destructor Destroy; override;
OutgoingMessages: TIdThreadSafeStringList;
end;
constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TIdContextThreadList = nil);
begin
inherited;
OutgoingMessages := TIdThreadSafeStringList.Create;
end;
destructor TMyContext.Destroy;
begin
OutgoingMessages.Free;
inherited;
end;
procedure TMyForm.FormCreate(Sender: TObject);
begin
// this must be set before activating the server...
IdTCPServer1.ContextClass := TMyContext;
end;
procedure TMyForm.IdTCPServer1Execute(AContext: TIdContext);
var
List, Messages: TStringList;
begin
// check for outgoing data...
Messages := nil;
try
List := TMyContext(AContext).OutgoingMessages.LockList;
try
if List.Count > 0 then
begin
Messages := TStringList.Create;
Messages.Assign(List);
List.Clear;
end;
finally
TMyContext(AContext).OutgoingMessages.UnlockList;
end;
if Messages <> nil then
begin
// send Messages using AContext.Connection.IOHandler as needed...
end;
finally
Messages.Free;
end;
// check for incoming data...
if AContext.Connection.IOHandler.InputBufferIsEmpty then
begin
AContext.Connection.IOHandler.CheckForDataOnSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
if AContext.Connection.IOHandler.InputBufferIsEmpty then
Exit;
end;
// process incoming data as needed...
end;
procedure TForm1.SomeProcedure;
var
List: TIdContextList;
Context: TMyContext;
begin
List := IdTCPServer1.Contexts.LockList;
try
Context := TMyContext(List[SomeIndex]);
Context.OutgoingMessages.Add('something');
finally
IdTCPServer1.Contexts.UnlockList;
end;
end;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.