2012-06-01 31 views
6

thisチュートリアルを使用して、書き込み可能セクションなしでJava nioサーバーを構築しています。Javaを使用した非同期サーバーNIO

すべてが1つの面白いことを除いて、正常に動作します。クライアントが速すぎてパケットを送信した場合、サーバーはすべてのメッセージを受信しません

  • 、サーバーは常に第一及び第二のパケットを取得していないが、それ以上。
  • クライアントがパケットをゆっくりと送信している場合、サーバーはすべてのパケットを取得します。

次のコードで言及している別のクラスが必要な場合は、サーバークラスコードを追加しています。私はここにいます:)私はあなたがUDPを読んでいた場合、その期待

package server; 
import java.io.IOException; 
import java.net.InetAddress; 
import java.net.InetSocketAddress; 
import java.net.Socket; 
import java.nio.ByteBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.ServerSocketChannel; 
import java.nio.channels.SocketChannel; 
import java.nio.channels.spi.SelectorProvider; 
import java.util.*; 

import javax.xml.parsers.ParserConfigurationException; 

import org.xml.sax.SAXException; 

public class NioServer implements Runnable { 



// The host:port combination to listen on 
    private InetAddress hostAddress; 
    private int port; 

    // The channel on which we'll accept connections 
    private ServerSocketChannel serverChannel; 

    // The selector we'll be monitoring 
    private Selector selector; 

    //the cach will hundle the messages that came 
    private Cache cache; 

    // The buffer into which we'll read data when it's available 
    private ByteBuffer readBuffer = ByteBuffer.allocate(8192); 

    public NioServer(InetAddress hostAddress, int port , Cache cache) throws IOException { 
    this.cache = cache; 
    this.hostAddress = hostAddress; 
    this.port = port; 
    this.selector = this.initSelector(); 
    } 


    private Selector initSelector() throws IOException { 
     // Create a new selector 
     Selector socketSelector = SelectorProvider.provider().openSelector(); 

     // Create a new non-blocking server socket channel 
     this.serverChannel = ServerSocketChannel.open(); 
     serverChannel.configureBlocking(false); 

     // Bind the server socket to the specified address and port 
     InetSocketAddress isa = new InetSocketAddress(this.hostAddress, this.port); 
     serverChannel.socket().bind(isa); 

     // Register the server socket channel, indicating an interest in 
     // accepting new connections 
     serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT); 

     return socketSelector; 
     } 

    private void accept(SelectionKey key) throws IOException { 
     // For an accept to be pending the channel must be a server socket channel. 
     ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); 

     // Accept the connection and make it non-blocking 
     SocketChannel socketChannel = serverSocketChannel.accept(); 
     Socket socket = socketChannel.socket(); 
     socketChannel.configureBlocking(false); 

     // Register the new SocketChannel with our Selector, indicating 
     // we'd like to be notified when there's data waiting to be read 
     socketChannel.register(this.selector, SelectionKey.OP_READ); 
     } 

    private void read(SelectionKey key) throws IOException { 
     SocketChannel socketChannel = (SocketChannel) key.channel(); 

     // Clear out our read buffer so it's ready for new data 
     this.readBuffer.clear(); 

     // Attempt to read off the channel 
     int numRead; 
     try { 
      numRead = socketChannel.read(this.readBuffer); 
      String test = new String(this.readBuffer.array()); 
      System.out.print(test); 

     } catch (IOException e) { 
      // The remote forcibly closed the connection, cancel 
      // the selection key and close the channel. 
     // key.cancel(); 
     // socketChannel.close(); 
      return; 
     } 

     if (numRead == -1) { 
      // Remote entity shut the socket down cleanly. Do the 
      // same from our end and cancel the channel. 
      key.channel().close(); 
      key.cancel(); 
      return; 
     } 

     // Hand the data off to our worker thread 
     this.cache.processData(this, socketChannel, this.readBuffer.array(), numRead); 
     } 

    public void run() { 
     while (true) { 
      try { 
      // Wait for an event one of the registered channels 

      this.selector.select(); 



      // Iterate over the set of keys for which events are available 
      Iterator selectedKeys = this.selector.selectedKeys().iterator(); 
      while (selectedKeys.hasNext()) { 
       SelectionKey key = (SelectionKey) selectedKeys.next(); 
       selectedKeys.remove(); 

       if (!key.isValid()) { 
       continue; 
       } 

       // Check what event is available and deal with it 
       if (key.isAcceptable()) { 
       this.accept(key); 
       } else if (key.isReadable()) { 
       this.read(key); 
       } 
      } 
      } catch (Exception e) { 
      e.printStackTrace(); 
      } 
     } 
     } 

    public static void main(String[] args) throws ParserConfigurationException, SAXException { 
    try { 
     Cache cache = new Cache(); 
     new Thread(cache).start(); 
     new Thread(new NioServer(null, 9090,cache)).start(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    } 
+3

コードにバグがあるはずです。より多くの助けが必要な場合は、より多くの情報をお知らせください。 –

+0

私は今コードを持っていない、私は日曜日にそれを持っています。ありがとう –

+3

TCPはデータを失わず、NIOもデータを失わない。あなたは、すべてのデータを読んでいないか、それをいくつか投げ捨てています。コメントするコードがなければ、それ以上コメントすることは不可能です。 – EJP

答えて

1

:NIOServerクラス

readメソッドでパケットを処理するのにどれだけ時間がかかることに注意してください。非常に遅いsystem.outに印刷していますが、processDataメソッドで他のスレッドにデータを処理する速度が不明です。 This library私が書いたのは、それが遅れの原因であれば、スレッド間のノンブロッキング通信を行うのに役立ちます。基礎となるリードソケットバッファのサイズもチェックする必要があります。それが大きいほど、パケットが落ち始める前にすばやくキャッチアップする必要がある部屋が増えます。 TCPの場合、基底のソケットバッファがいっぱいになると、おそらくチャネルでIOExceptionが発生します。 UDPの場合、パケットは静かにドロップされます。

あなたがすることができる基本的な読み取りソケットバッファサイズへのアクセスました:

final Socket socket = channel.socket(); 
System.out.println(socket.getReceiveBufferSize()); 
socket.setReceiveBufferSize(newSize); 

注:私の知る限り、Linuxはあなたが基本となるバッファサイズを変更するためには、いくつかのOSの設定が必要になることがあります。 setReceiveBufferSizeに何も影響がない場合(変更されたかどうかを再度確認してください)、googleに関する情報があります。 :)

関連する問題