2009-07-20 27 views
2

私はチャットサーバと現在、私の設計は、次の基づいているベースのJavaを書いています: - チャットルームにいる人は、メッセージを送信し、サーバ側のチャットルームのクラスは、すべてに同じメッセージを送信するとき参加者は部屋の中をループします。明らかに、これは、ループが個々の参加者にネットワーク通話が行われているため、貧弱な設計です。したがって、たとえば、チャットルームに10人いるとします。 1人のユーザーがメッセージを送信すると、chatroomクラスはループ内で同じメッセージを10人全員に送信します。言い換えれば、ループの第5人が冗談な接続をしている場合、第6 ..第10人がメッセージを見る時間が影響を受けます。Javaのチャットサーバー

私は部屋ごとにマルチキャスト、ユニキャストから移動した場合、その後、どのように私はチャットルームあたりのプライベートマルチキャストグループのIPを得るのですか?また、チャットルームごとに個別のグループを持つことは過度のようです。 主な問題の1つは、ループを介して部屋のユーザーに返信したときに、ソケット接続でデータを送信したメソッドがブロックされていたことです。したがって、私は非ブロックNIOソケットを使用し、受信者にループでメッセージを送信すると思っているが、それは問題を解決するだろうか? 部屋の受信者にデータを送信するのを最適化するために他にも巧妙なやり方がありますか?

+0

人が読めるように段落に分割してみてください。 – cdmckay

答えて

3

単純な実装は、クライアントごとに2つのスレッドを使用することです。ソケットから読み取るスレッドとソケットに書き込むスレッド。クライアントが少ない場合、これは問題ありません。あなたは多くのクライアントを扱うためにNIOを知る必要があります。 (スレッドモデルがうまく動作しない「多くの」意味。)

クライアントの読み取りスレッドがソケットからメッセージ全体を読み取り、チャットルームオブジェクト内のキューに入れます。チャットルームには、メッセージをキューから取り出してクライアントのキューに入れるスレッドがあります。スレッドを書くクライアントは、そのキューをポーリングし、そのメッセージをソケットに書き込みます。

チャットルームには、接続を受け入れ、クライアントオブジェクトを作成するためのスレッドを持っており、コレクションでそれらを置きます。メッセージキューをポーリングしてメッセージをクライアントキューに配信する別のスレッドがあります。

Apache MinaはNIO

+0

クライアントごとに2つのスレッドとポーリングとスリープの両方のスレッドを使用すると、VMによるコンテキスト切り替えとスレッドスケジューリングのオーバーヘッドがクライアントの数に比例して増加します。デュアルコアプロセッサなどの汎用ハードウェアにデプロイすることをお勧めします。私はVMスケジューラがCPUを殆ど避けて動作させてくれると考えています –

+0

クライアントとして言及した唯一の番号は10です。私の経験では、どのようなハードウェアでも10人のチャットが可能です。 – Clint

+1

@ Maninder Batthあなたはhttp://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-thanを見ましたか?html – grom

2

私はシリアルに受信者をループすることは悪い考えであろうことに同意を使用する例があります。このために、ThreadPoolを使用して手助けをすることを検討することができます。しかし、私はマルチキャストがあなたの最善の策だと思うでしょう。チャットルームモデルに適しています。あなたは一度だけ送る必要があり、あなたの反復的なアプローチは解決されます。アドレスに異なるポートを指定することで、一意のグループIDを取得できます。

+0

私は、JavaのマルチキャストはUDPだけをサポートしていると考えています。これは、受信者からの何らかのACKなしでメッセージ配信が成功したかどうかをサーバーが判断できないことを意味します。 –

+0

私はそれを非常に一般化された製品にしようとしており、一部のクライアントネットワークがマルチキャスティングをサポートしていない可能性があります。したがって、私はマルチキャスティングのアプローチで行くことに躊躇しています –

+0

@Zach Scrivena:私は同意します。マルチキャストの効率のトレードオフはデータの整合性(データの順序と潜在的な損失)の喪失です。しかし、チャットルームのようなものについては、それは実行可能な貿易と見なされます。 – akf

2

単純なアプローチは、クライアント接続ごとに2つのスレッドを使用することです。 1つのスレッドは、メッセージを送信するためにクライアントからのメッセージの読み取りを処理し、それによって同時にクライアントからメッセージを送受信することができます。メッセージをブロードキャストするクライアント接続をループする際に、サーバースレッドがクライアントに送信するキューにメッセージを追加する必要がありますネットワーク呼び出しを避けるために

。 java.util.concurrentのLinkedBlockingQueueはこれに最適です。以下はその例です:

/** 
* Handles outgoing communication with client 
*/ 
public class ClientConnection extends Thread { 
    private Queue<String> outgoingMessages = new LinkedBlockingQueue<String>(MAX_OUTGOING); 
    // ... 
    public void queueOutgoing(String message) { 
     if (!outgoingMessages.offer(message)) { 
      // Kick slow clients 
      kick(); 
     } 
    } 

    public void run() { 
     // ... 
     while (isConnected) { 
      List<String> messages = new LinkedList<String>(); 
      outgoingMessages.drainTo(messages); 
      for (String message : messages) { 
       send(message); 
      } 
      // ... 
     } 
    } 
} 

public class Server { 
    // ... 
    public void broadcast(String message) { 
     for (ClientConnection client : clients) { 
      client.queueOutgoing(message); 
     } 
    } 
} 
+0

したがって、サーバーあたりのスレッド数はaproxになります。 - 人数* 2.チャットサーバーあたり1000人以上でサービスしたいとします。また、ハードウェアマシンごとに少なくとも5つのサーバーが必要です。また、ハードウェアがデュアルコアサーバーであると仮定します。 したがって、デュアルコアマシンでは、サーバーあたり2000スレッド、5サーバーあたり10スレッド。少なくとも50%のスレッドがいつでもアクティブで、デュアルコアあたり5kスレッドで、コンテキストの切り替えやスレッドのスケジューリングに時間がかかり過ぎることがあります。コメントはありますか? –

+0

NPTLは多くの接続を処理できます。 http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.htmlを参照してください。 – grom

関連する問題