簡體   English   中英

Indy 10 TCP服務器

[英]Indy 10 TCP server

經過大量的搜索,我認為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;

是的,您必須遍歷Contexts列表才能向多個客戶端廣播消息。 但是,您不(也不應該)從循環內部執行實際寫入。 其中一個,正如您已經注意到的那樣,通過保持列表鎖定一段時間可以影響服務器性能。 二,它不是線程安全的。 如果您的循環將數據寫入連接而另一個線程同時寫入同一連接,則這兩個寫入將相互重疊並破壞與該客戶端的通信。

我通常做的是實現每個客戶端的出站隊列,使用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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM