1

以下で説明するのは技術的にマルチキャストではないことは知っていますが、私がやろうとしていることについてのより良い説明が不足しています。

現在、OnExecuteを備えたTIdTCPServerがあり、着信メッセージを読み取り、応答メッセージをスレッドセーフキューに生成してから、関数を呼び出してキューをステップスルーし、メッセージをクライアントに送り返します。コードのこの部分は機能しており、クライアントがデータセットを要求できるようにします。

クライアントがサーバー上のオブジェクトを変更したときに、すべてのクライアントにこの変更を通知してもらいたいです。このコードは現在、接続ごとに各キューに通知メッセージを追加しています。私の問題は、OnExecuteがループされていないため、サーバーがクライアントからメッセージを受信するまで、キューにメッセージを送信するための呼び出しが呼び出されないことです。

OnExecuteをループさせる方法はありますか?または、メッセージをキューに入れていることがわかっている接続に対してOnExecuteをトリガーする方法はありますか?

私のプロシージャTWinSocketSessionオブジェクトには接続への参照があり、送信メッセージキューのコードが含まれています。また、キューをステップスルーしてConnection.Writeを呼び出すSendMessagesというプロシージャもあります。以下は私のOnExecuteプロシージャです。

procedure TWinServerSession.IdTCPServer1Execute(AThread: TIdPeerThread);
  Var
    i:           Integer;
    strMessage:  String;
  begin
    //find the Socket Session for connection
    for i := 0 to m_usClientCount do
      begin
        if m_mWinSocketSession[i]<>Nil then
          if ( m_mWinSocketSession[i].Connection = Athread.Connection ) then break;
      end;

    //read the message
    strMessage := m_mWinSocketSession[i].Connection.ReadLn(#0,25,-1);

    //parse the message and populate the Queue with outgoing messages
    m_mWinSocketSession[i].ParseInString(strMessage);

    //send all of the outgoing messages
    m_mWinSocketSession[i].SendMessages;
  end;
4

1 に答える 1

3

はい、TIdTCPServer.OnExecuteイベントはループイベントです。インバウンドメッセージが到着したときにトリガーされません。接続が実際に何をしているかに関係なく、接続の存続期間中、継続的なループでトリガーされます。必要に応じてブロッキング動作を実装するのは、イベントハンドラーの責任です。コードはReadLn()25msのタイムアウトを指定して呼び出しているため、イベントハンドラーがタイムリーに終了するのをブロックしないため、すぐに再入力できます。イベントハンドラーがタイムリーに終了するのをブロックされている場合は、コードの他の場所でデッドロックの問題が発生しています。

ただし、次の変更をお勧めします。

procedure TWinServerSession.IdTCPServer1Connect(AThread: TIdPeerThread); 
var
  i: Integer;
begin 
  for i := 0 to m_usClientCount do  
  begin  
    if (m_mWinSocketSession[i] = nil) then
    begin
      m_mWinSocketSession[i] := TWinSocketSession.Create;
      m_mWinSocketSession[i].Connection := AThread.Connection;

      // for easier access in the other events...
      AThread.Data := m_mWinSocketSession[i];  

      Exit;
    end;
  end;

  // cannot start a new session
  AThread.Connection.Disconnect;
end; 

procedure TWinServerSession.IdTCPServer1Disconnect(AThread: TIdPeerThread); 
var
  session: TWinSocketSession;
  i: Integer;
begin 
  session := TWinSocketSession(AThread.Data);
  AThread.Data := nil;

  if session <> nil then
  begin      
    for i := 0 to m_usClientCount do  
    begin  
      if m_mWinSocketSession[i] = session then
      begin
        m_mWinSocketSession[i] := nil;
        Break;
      end;
    end;
    session.Free;
  end;
end; 

procedure TWinServerSession.IdTCPServer1Execute(AThread: TIdPeerThread); 
var 
  session: TWinSocketSession;
  strMessage:  String; 
begin 
  session := TWinSocketSession(AThread.Data);

  //read a message  
  strMessage := AThread.Connection.ReadLn(#0, 25, -1);  
  if not AThread.Connection.ReadLnTimedOut then
  begin
    //parse the message and populate the Queue with outgoing messages  
    session.ParseInString(strMessage);  
  end;

  //send all of the outgoing messages  
  session.SendMessages;  
end; 

OnConnectこれは、m_mWinSocketSessionリストを完全に削除し、イベントで接続に直接新しいキューを割り当てることができれば、さらにうまく機能します。イベントはOnDisconnect、クライアントが切断したときにキューを解放できます。

procedure TWinServerSession.IdTCPServer1Connect(AThread: TIdPeerThread); 
begin
  AThread.Data := TWinSocketSession.Create;
  TWinSocketSession(AThread.Data).Connection := AThread.Connection;
end;

procedure TWinServerSession.IdTCPServer1Disconnect(AThread: TIdPeerThread); 
begin
  session := TWinSocketSession(AThread.Data);
  AThread.Data := nil;
  session.Free;
end;
于 2012-07-12T21:09:17.420 に答える