微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

delphi – Indy 10 TCP服务器

经过大量的搜索,我认为Indy TCP服务器最适合在我正在使用的Instant Messenger服务器上使用.我现在面临的唯一问题是向其他连接的客户端广播和转发消息,向同一客户端发送回响应似乎没有,并且不会挂起其他客户端活动,但是为了将消息转发给其他客户端我知道的机制是通过使用aContext.locklist,并在连接列表之间迭代,以找到要接收数据的客户端连接.

我认为这里的问题是它会冻结列表,并且在调用unlocklist之前不会处理其他客户端请求.那么它不会损害服务器的性能吗?锁定列表并在连接之间进行迭代以转发每条消息(因为这是在信使中经常发生的事情).有没有更好的方法来做到这一点?

我使用的是Indy 10和Delphi 7

广播代码

Var tmpList: TList;
    i: Integer;
Begin
tmpList := IdServer.Contexts.LockList;

For i := 0 to tmpList.Count Do Begin
  TIdContext(tmpList[i]).Connection.socket.WriteLn('broadcast message');
End;
IdServer.Contexts.UnlockList;

转发邮件代码

Var tmpList: TList;
  i: Integer;
Begin
  tmpList := IdServer.Contexts.LockList;

  For i := 0 to tmpList.Count Do Begin
    If TIdContext(tmpList[i]).Connection.socket.Tag = idReceiver Then
      TIdContext(tmpList[i]).Connection.socket.WriteLn('Message');
  End;
  IdServer.Contexts.UnlockList;

解决方法

是的,您必须遍历上下文列表才能向多个客户端广播消息.但是,您没有(也不应该)从循环内部执行实际写入.一,正如您已经注意到的那样,通过保持列表锁定一段时间可以影响服务器性能.二,它不是线程安全的.如果您的循环将数据写入连接而另一个线程同时写入同一连接,则这两个写入将相互重叠并破坏与该客户端的通信.

我通常做的是实现每个客户端的出站队列,使用TIdContext.Data属性或TIdServerContext后代来保存实际队列.当您需要从该客户端的OnExecute事件外部向客户端发送数据时,请将数据放入该客户端的队列中.然后,客户端的OnExecute事件可以在安全的情况下将队列的内容发送到客户端.

例如:

type
  TMyContext = class(TIdServerContext)
  public
    Tag: Integer;
    Queue: TIdThreadSafeStringList;
    ...
    constructor Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil); override;
    destructor Destroy; override;
  end;

constructor TMyContext.Create(AConnection: TIdTCPConnection; AYarn: TIdYarn; AList: TThreadList = nil);
begin
  inherited;
  Queue := TIdThreadSafeStringList.Create;
end;

destructor TMyContext.Destroy;
begin
  Queue.Free;
  inherited;
end;

.

procedure TForm1.FormCreate(Sender: TObject);
begin
  IdServer.ContextClass := TMyContext;
end;

procedure TForm1.IdServerConnect(AContext: TIdContext);
begin
  TMyContext(AContext).Queue.Clear;
  TMyContext(AContext).Tag := ...
end;

procedure TForm1.IdServerdisconnect(AContext: TIdContext);
begin
  TMyContext(AContext).Queue.Clear;
end;

procedure TForm1.IdServerExecute(AContext: TIdContext);
var
  Queue: TStringList;
  tmpList: TStringList;
begin
  ...
  tmpList := nil;
  try
    Queue := TMyContext(AContext).Queue.Lock;
    try
      if Queue.Count > 0 then
      begin
        tmpList := TStringList.Create;
        tmpList.Assign(Queue);
        Queue.Clear;
      end;
    finally
      TMyContext(AContext).Queue.Unlock;
    end;
    if tmpList <> nil then
      AContext.Connection.IOHandler.Write(tmpList);
  finally
    tmpList.Free;
  end;
  ...
end;

.

var
  tmpList: TList;
  i: Integer;
begin
  tmpList := IdServer.Contexts.LockList;
  try
    for i := 0 to tmpList.Count-1 do
      TMyContext(tmpList[i]).Queue.Add('broadcast message');
  finally
    IdServer.Contexts.UnlockList;
  end;
end;

.

var
  tmpList: TList;
  i: Integer;
begin
  tmpList := IdServer.Contexts.LockList;
  try
    for i := 0 to tmpList.Count-1 do
    begin
      if TMyContext(tmpList[i]).Tag = idReceiver then
        TMyContext(tmpList[i]).Queue.Add('Message');
    end;
  finally
    IdServer.Contexts.UnlockList;
  end;
end;

原文地址:https://www.jb51.cc/delphi/103048.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐