2009-08-01 14 views
3

さて、私はここに夢中になります。私は自分のサーバーのNIOコードを書き直していて、本当に頭痛に冒されています。要するに、NIOを「正しい」ものにすることは非常に難しいことです。 Roxチュートリアルhttp://rox-xmlrpc.sourceforge.net/niotut/に私を指し示した人もいますが、これは良い方法だと思われますが、私が望むほど完全ではありません。たとえば、送信側のByteBuffersが送信された後にのみ、サーバー側で接続を閉じる方法を知る必要があります。 SocketChannel.close()は突然終了し、早すぎるとデータが失われる可能性があります。私はまた、読み込まれたByteBufferより大きい大きなパケットを送る必要があります。 Roxコード(これまで見た他のコードも)はこれを扱っています。捕らえられていない例外が適切に処理されないような場所も数多くあります。私のテストではいくつかのエラーがあり、NIOの複雑さを考慮すると、それらを適切に処理する方法が明確ではありません。Java:スレッドごとの接続をブロックするコード例IO対NIO?

私がこれらの問題を解決しようとすると、もっと複雑な微妙な部分が現れ、かなり複雑になっています。だから、私はまったく異なるアプローチを考えている。多くの人々は、NIOはエラーが起こりやすく、不必要に混乱し複雑であると言っています。彼らは、各ソケット接続が独自のスレッドで実行されるブロッキングIOを使用する「接続ごとのスレッド」モデルを使用することを推奨しています。これは良いアイデアのように思えますが、NIOのようにすべての接続に対して1つのセレクタスレッドを用意することでフロントエンドのボトルネックを減らし、オーバーヘッドが高くなります(スレッド用)。この感想はhttp://paultyma.blogspot.com/2008/03/writing-java-multithreaded-servers.htmlhttp://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html

などの投稿でエコーされます。コードはNIOに比べてシンプルでなければなりませんが、実際には見たいコードがほしいです。私は何かを見つけることができない。問題は、この「スレッドごとの接続をブロックするI/O」戦略が実際に良いGoogle結果を得るためのより良い名前だとは思わないということです。誰かがこのI/Oの "古い"方法を使って説明し、スレッドプールを使ってそれを拡大する方法を説明するために、いくつかのチュートリアルや簡単な例にリンクできますか?あるいは知恵の他の言葉を持っている?どうもありがとう!

+0

'SocketChannel.close()'は*あなたのアプリケーション*がそれをまだ送っていない限り、*破棄せず*データを失うことはできません。 – EJP

答えて

0

JDKのsample/nioディレクトリを参照することをお勧めします。これには、あなたが言及している2つの例を含む、いくつかの簡単な例があります。

0

NIOを直接使用するのではなく、Grizzlyなどの上位レベルのフレームワークを使用することを検討することもできます。このフレームワークでは、NIOの微妙なことではなく、ユースケースに集中する必要があります。

+1

JbossにはNettyもあります:http://www.jboss.org/netty – Dave

1

NIOで作業している場合は、フレームワークを使用することもお勧めします。私はApache Minaと働いており、私はそれをお勧めします。

ブロックIOでは、着信接続を受け入れ、各接続を処理する追加のスレッドを生成するリスナースレッドが必要になります。最初はApache Felixプロジェクトに貢献したリスナーコードの例です。 完全であるが変更されたバージョンを探す場合は、browse the source hereとすることができます。

/* 
    * Licensed to the Apache Software Foundation (ASF) under one or more 
    * contributor license agreements. See the NOTICE file distributed with 
    * this work for additional information regarding copyright ownership. 
    * The ASF licenses this file to You under the Apache License, Version 2.0 
    * (the "License"); you may not use this file except in compliance with 
    * the License. You may obtain a copy of the License at 
    * 
    *  http://www.apache.org/licenses/LICENSE-2.0 
    * 
     * Unless required by applicable law or agreed to in writing, software 
    * distributed under the License is distributed on an "AS IS" BASIS, 
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
    * See the License for the specific language governing permissions and 
    * limitations under the License. 
    */ 
    package org.apache.felix.shell.remote; 


    import java.io.IOException; 
    import java.io.PrintStream; 
    import java.net.ServerSocket; 
    import java.net.Socket; 
    import java.net.SocketException; 


    /** 
    * Implements a simple listener that will accept a single connection. 
    * <p/> 
    * 
    * @author Dieter Wimberger (wimpi) 
    */ 
    class Listener 
    { 

     private int m_Port; 
     private Thread m_ListenerThread; 
     private boolean m_Stop = false; 
     private ServerSocket m_ServerSocket; 
     private AtomicInteger m_UseCounter; 
     private int m_MaxConnections; 


     /** 
     * Activates this listener on a listener thread (telnetconsole.Listener). 
     */ 
     public void activate() 
     { 
      //configure from system property 
      try 
      { 
       m_Port = Integer.parseInt(System.getProperty("osgi.shell.telnet.port", "6666")); 
      } 
      catch (NumberFormatException ex) 
      { 
       Activator.getServices().error("Listener::activate()", ex); 
      } 
      try 
      { 
       m_MaxConnections = Integer.parseInt(System.getProperty("osgi.shell.telnet.maxconn", "2")); 
      } 
      catch (NumberFormatException ex) 
      { 
       Activator.getServices().error("Listener::activate()", ex); 
      } 
      m_UseCounter = new AtomicInteger(0); 
      m_ListenerThread = new Thread(new Acceptor(), "telnetconsole.Listener"); 
      m_ListenerThread.start(); 
     }//activate 


     /** 
     * Deactivates this listener. 
     * <p/> 
     * The listener's socket will be closed, which should cause an interrupt in the 
     * listener thread and allow for it to return. The calling thread joins the listener 
     * thread until it returns (to ensure a clean stop). 
     */ 
     public void deactivate() 
     { 
      try 
      { 
       m_Stop = true; 
       //wait for the listener thread 
       m_ServerSocket.close(); 
       m_ListenerThread.join(); 
      } 
      catch (Exception ex) 
      { 
       Activator.getServices().error("Listener::deactivate()", ex); 
      } 
     }//deactivate 

     /** 
     * Class that implements the listener's accept logic as a <tt>Runnable</tt>. 
     */ 
     private class Acceptor implements Runnable 
     { 

      /** 
      * Listens constantly to a server socket and handles incoming connections. 
      * One connection will be accepted and routed into the shell, all others will 
      * be notified and closed. 
      * <p/> 
      * The mechanism that should allow the thread to unblock from the ServerSocket.accept() call 
      * is currently closing the ServerSocket from another thread. When the stop flag is set, 
      * this should cause the thread to return and stop. 
      */ 
      public void run() 
      { 
       try 
       { 
        /* 
         A server socket is opened with a connectivity queue of a size specified 
         in int floodProtection. Concurrent login handling under normal circumstances 
         should be handled properly, but denial of service attacks via massive parallel 
         program logins should be prevented with this. 
        */ 
        m_ServerSocket = new ServerSocket(m_Port, 1); 
        do 
        { 
         try 
         { 
          Socket s = m_ServerSocket.accept(); 
          if (m_UseCounter.get() >= m_MaxConnections) 
          { 
           //reject with message 
           PrintStream out = new PrintStream(s.getOutputStream()); 
           out.print(INUSE_MESSAGE); 
           out.flush(); 
           //close 
           out.close(); 
           s.close(); 
          } 
          else 
          { 
           m_UseCounter.increment(); 
           //run on the connection thread 
           Thread connectionThread = new Thread(new Shell(s, m_UseCounter)); 
           connectionThread.start(); 
          } 
         } 
         catch (SocketException ex) 
         { 
         } 
        } 
        while (!m_Stop); 

       } 
       catch (IOException e) 
       { 
        Activator.getServices().error("Listener.Acceptor::activate()", e); 
       } 
      }//run 

     }//inner class Acceptor 

     private static final String INUSE_MESSAGE = "Connection refused.\r\n" 
      + "All possible connections are currently being used.\r\n"; 

    }//class Listener 

あなたは他の例を見つけることができherehere

NIOがブロッキングモデルよりも優れている点は、負荷が増えたときです。ある時点から、スレッドの作成、管理、コンテキスト切り替えの余分な作業がシステムのパフォーマンスを制限します。

関連する問題