Multithreading 如何在已经运行的线程中运行代码以安全地发送/recv数据[TidTCPServer]
更新问题仍然存在 可以在已经运行的线程中运行代码吗?例如: thread1正在运行一些代码&我想在thread1中运行thread2中的代码Multithreading 如何在已经运行的线程中运行代码以安全地发送/recv数据[TidTCPServer],multithreading,delphi,thread-safety,indy,delphi-xe8,Multithreading,Delphi,Thread Safety,Indy,Delphi Xe8,更新问题仍然存在 可以在已经运行的线程中运行代码吗?例如: thread1正在运行一些代码&我想在thread1中运行thread2中的代码 我想在idTCPServer线程中运行代码,以便向客户端发送一些数据 编辑: 经过研究,我的问题似乎是,当客户端数据被接收或同时被另一个线程试图写入该套接字时 编辑: procedure TMainFrm.UserSRVExecute(AContext: TIdContext); var Command : String; msSize
我想在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;
...
过程tmainfm.UserSRVExecute(AContext:TIdContext);
变量
命令:字符串;
msSize:Int64;
ms:TMemoryStream;
解压缩DMS:TMemoryStream;
H:TID通知;
开始
//Application.ProcessMessages;
命令:=AContext.Connection.Socket.ReadLn;
//消息框(0,'snd','',40美元);
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-BEGIN');
如果命令为“”,则//keepalive
开始
//Application.ProcessMessages;
msSize:=AContext.Connection.Socket.ReadInt64;
ms:=TMemoryStream.Create;
解压缩DMS:=TMemoryStream.Create;
尝试
AContext.Connection.Socket.ReadStream(ms,msSize);
女士职位:=0;
解压流(MS,解压DMS);
解压DMS.位置:=0;
客户端处理数据(文本、命令、解压DMS);
最后
弗里女士;
解压dms.Free;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-END');
结束;
结束;
结束;
过程客户机_ProcessData(AContext:TIdContext;cmd:String;data:TMemoryStream);
变量
Hnd:THandle;
clData:TStringArray;
TmpStr1:字符串;
Tmp:字符串;
TN:TIdNotify;
同步:TMySync;
一、 I2:整数;
开始
Hnd:=AContext.Connection.Socket.Binding.Handle;
如果cmd='scr',则//RECEIVE命令发送到客户端以从客户端接收数据
开始
Tmp:=StreamToString(数据);
{Sync:=TMySync2.Create(True);
尝试
Sync.cmd:=cmd;
Sync.hnd:=hnd;
Sync.tmp:=TmpStr1;
同步。恢复;
最后
//同步。免费;
结束;}
log('>>>CLFROMAS:'+IntToStr(HND)+':'+cmd+':');
//SendCMDToSocket(MainFrm.UserSRV、stroint(Trim(Tmp))、'scr'+IntToStr(Hnd));
I2:=stroint(微调(Tmp));
对于I:=0到100 do
如果USRVData[i].hnd=I2,则
开始
//cs.收购;
USRVData[i].CTX.Connection.Socket.WriteLn('scr'+IntToStr(Hnd));//将所有上下文放置在全局变量+所有套接字句柄中。长度('scr4u'),然后
开始
删除(cmd,1,长度('scr4u'));
数据位置:=0;
{Sync:=TMySync.Create;
尝试
Sync.cmd:=cmd;
Sync.hnd:=hnd;
Sync.data:=TMemoryStream.Create;
Sync.data.CopyFrom(数据、数据、大小);
Sync.data.Position:=0;
Sync.DoNotify;
最后
Sync.data.Free;
同步。免费;
结束;}
SendStreamToSocket(MainFrm.UserSRV,stroint(cmd),'scr4u',数据);
日志('>>>>管理员:'+IntToStr(HND)+'::'+cmd+'::'{+streamtostring(data)});
end else TmpStr1:='';
出口
结束;
...
更新
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;
过程tmainfm.UserSRVExecute(AContext:TIdContext);
变量
命令:字符串;
msSize:Int64;
ms:TMemoryStream;
解压缩DMS:TMemoryStream;
H:TID通知;
I:整数;
列表,消息:TStringList;
开始
讯息:=nil;
尝试
列表:=TMyContext(AContext).OutgoingMessages.Lock;
尝试
如果List.Count>0,则
开始
消息:=TStringList.Create;
消息分配(列表);
列表。清晰;
结束;
最后
TMyContext(AContext).OutgoingMessages.Unlock;
结束;
如果消息为零,则
开始
对于I:=0到Messages.Count-1 do
开始
AContext.Connection.IOHandler.WriteLn(Messages.Strings[I]);
结束;
结束;
最后
信息。免费;
结束;
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
开始
AContext.Connection.IOHandler.checkforDataSource(100);
AContext.Connection.IOHandler.CheckForDisconnect;
如果AContext.Connection.IOHandler.InputBufferIsEmpty,则
出口
结束;
命令:=AContext.Connection.Socket.ReadLn;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-BEGIN');
如果命令为“”,则
开始
msSize:=AContext.Connection.Socket.ReadInt64;
ms:=TMemoryStream.Create;
解压缩DMS:=TMemoryStream.Create;
尝试
AContext.Connection.Socket.ReadStream(ms,msSize);
女士职位:=0;
解压流(MS,解压DMS);
解压DMS.位置:=0;
客户端处理数据(文本、命令、解压DMS);
最后
弗里女士;
解压dms.Free;
如果是logb,则mainfrm.mconnections.Lines.Add(命令+'-END');
结束;
结束;
结束;
可以在已经运行的线程中运行代码吗?例如:thread1正在运行一些代码&我想在thread1中运行thread2中的代码
不需要。Thread1需要显式编码,以停止它当前正在执行的操作,执行其他操作,然后返回到以前的操作。Thread2所能做的就是向Thread1发出信号,让其尽早执行停止+继续操作
我想在idTCPServer线程中运行代码,以便向客户端发送一些数据 您的
TIdTCPServer.OnExecute
事件处理程序需要定期检查该数据,并在数据可用时发送
您可以使用TIdContext.Data
属性,或从TIdServerContext
派生自定义类,并将其分配给tidcpserver.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;