gpt4 book ai didi

delphi - 没有 OnExecute 事件的 TCPserver

转载 作者:行者123 更新时间:2023-12-03 15:17:36 35 4
gpt4 key购买 nike

我想创建一个 TCPserver 并根据需要向客户端发送/接收消息,而不是 TCPserver 的 OnExecute 事件。

发送/接收消息没有问题;我确实喜欢这样:

procedure TFormMain.SendMessage(IP, Msg: string);
var
I: Integer;
begin
with TCPServer.Contexts.LockList do
try
for I := 0 to Count-1 do
if TIdContext(Items[I]).Connection.Socket.Binding.PeerIP = IP then
begin
TIdContext(Items[I]).Connection.IOHandler.WriteBuffer(Msg[1], Length(Msg));
// and/or Read
Break;
end;
finally
TCPServer.Contexts.UnlockList;
end;
end;

注1:如果我不使用OnExecute,程序会在客户端连接时引发异常。
注 2:如果我不执行任何操作就使用 OnExecute,CPU 使用率将达到 %100
注 3:我没有机会更改 TCP 客户端。

那我该怎么办?

最佳答案

TIdTCPServer 需要默认分配的 OnExecute 事件处理程序。为了解决这个问题,您必须从 TIdTCPServer 派生一个新类并重写其虚拟 CheckOkToBeActive() 方法,并且还应该重写虚拟 DoExecute() 调用 Sleep()。否则,只需分配一个事件处理程序并让它调用 Sleep()

但这并不是 TIdTCPServer 的有效使用。更好的设计是不要直接从 SendMessage() 方法内部将出站数据写入客户端。这不仅容易出错(您没有从 WriteBuffer() 捕获异常)并在写入期间阻止 SendMessage(),而且它还会序列化您的通信(客户端 2 无法接收数据,直到客户端 1 首先接收数据)。更有效的设计是为每个客户端提供自己的线程安全出站队列,然后让 SendMessage() 根据需要将数据放入每个客户端的队列中。然后,您可以使用 OnExecute 事件检查每个客户端的队列并进行实际写入。这样,SendMessage() 就不会再被阻塞,更不容易出错,并且可以并行写入客户端(就像它们应该的那样)。

尝试这样的事情:

uses
..., IdThreadSafe;

type
TMyContext = class(TIdServerContext)
private
FQueue: TIdThreadSafeStringList;
FEvent: TEvent;
public
constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override;
destructor Destroy; override;
procedure AddMsgToQueue(const Msg: String);
function GetQueuedMsgs: TStrings;
end;

constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil);
begin
inherited;
FQueue := TIdThreadSafeStringList.Create;
FEvent := TEvent.Create(nil, True, False, '');
end;

destructor TMyContext.Destroy;
begin
FQueue.Free;
FEvent.Free;
inherited;
end;

procedure TMyContext.AddMsgToQueue(const Msg: String);
begin
with FQueue.Lock do
try
Add(Msg);
FEvent.SetEvent;
finally
FQueue.Unlock;
end;
end;

function TMyContext.GetQueuedMsgs: TStrings;
var
List: TStringList;
begin
Result := nil;
if FEvent.WaitFor(1000) <> wrSignaled then Exit;
List := FQueue.Lock;
try
if List.Count > 0 then
begin
Result := TStringList.Create;
try
Result.Assign(List);
List.Clear;
except
Result.Free;
raise;
end;
end;
FEvent.ResetEvent;
finally
FQueue.Unlock;
end;
end;

procedure TFormMain.FormCreate(Sender: TObject);
begin
TCPServer.ContextClass := TMyContext;
end;

procedure TFormMain.TCPServerExecute(AContext: TIdContext);
var
List: TStrings;
I: Integer;
begin
List := TMyContext(AContext).GetQueuedMsgs;
if List = nil then Exit;
try
for I := 0 to List.Count-1 do
AContext.Connection.IOHandler.Write(List[I]);
finally
List.Free;
end;
end;

procedure TFormMain.SendMessage(const IP, Msg: string);
var
I: Integer;
begin
with TCPServer.Contexts.LockList do
try
for I := 0 to Count-1 do
begin
with TMyContext(Items[I]) do
begin
if Binding.PeerIP = IP then
begin
AddMsgToQueue(Msg);
Break;
end;
end;
end;
finally
TCPServer.Contexts.UnlockList;
end;
end;

关于delphi - 没有 OnExecute 事件的 TCPserver,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9324723/

35 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com