2012-03-16 65 views
0

我是新的Java NIO,閱讀了一些教程後,我試圖自己寫一個簡單的NIO服務器和客戶端。 我的服務器只是做一件簡單的事情是從客戶端偵聽並打印到控制檯,客戶端只是連接到服務器併發送給它3條消息「你好」。 問題是我的服務器監聽並且與3條消息一起工作良好,之後它應該被阻塞並繼續監聽,但它不會,沒有阻塞,它在無限循環時運行它。這裏是我的服務器和客戶端:無限循環與選擇器即使沒有連接客戶端

服務器

import java.net.InetSocketAddress; 
import java.nio.ByteBuffer; 
import java.nio.CharBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.ServerSocketChannel; 
import java.nio.channels.SocketChannel; 
import java.nio.charset.Charset; 
import java.nio.charset.CharsetDecoder; 
import java.util.Iterator; 
import java.util.Set; 

public class Server { 
    public static void main(String args[]) throws Exception { 
     // Create the server socket channel 
     ServerSocketChannel server = ServerSocketChannel.open(); 
     // nonblocking I/O 
     server.configureBlocking(false); 
     // host-port 8000 
     server.socket().bind(new InetSocketAddress(8000)); 
     System.out.println("Server actives at port 8000"); 
     // Create the selector 
     Selector selector = Selector.open(); 
     // Recording server to selector (type OP_ACCEPT) 
     server.register(selector, SelectionKey.OP_ACCEPT); 

     while (selector.select() > 0) { 

      // Get keys 
      Set<SelectionKey> keys = selector.selectedKeys(); 
      Iterator<SelectionKey> i = keys.iterator(); 

      // print 
      System.out.println("[ " + keys.size() + " ]"); 

      // For each keys... 
      while (i.hasNext()) { 
       SelectionKey key = (SelectionKey) i.next(); 
       // Remove the current key 
       i.remove(); 

       // if isAccetable = true 
       // then a client required a connection 
       if (key.isAcceptable()) { 
        // get client socket channel 
        SocketChannel client = server.accept(); 
        // Non Blocking I/O 
        client.configureBlocking(false); 
        // recording to the selector (reading) 
        client.register(selector, SelectionKey.OP_READ); 
        continue; 
       } 

       // if isReadable = true 
       // then the server is ready to read 
       if (key.isReadable()) { 

        SocketChannel client = (SocketChannel) key.channel(); 

        // Read byte coming from the client 
        int BUFFER_SIZE = 1024; 
        ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); 
        try { 
         client.read(buffer); 
        } catch (Exception e) { 
         // client is no longer active 
         e.printStackTrace(); 
        } 

        // Show bytes on the console 
        buffer.flip(); 
        Charset charset = Charset.forName("ISO-8859-1"); 
        CharsetDecoder decoder = charset.newDecoder(); 
        CharBuffer charBuffer = decoder.decode(buffer); 
        System.out.println("[" + charBuffer.toString() + "]"); 
       } 
      } 
     } 
    } 
} 

,這裏是我的客戶:

import java.nio.ByteBuffer; 
import java.nio.channels.SelectionKey; 
import java.nio.channels.Selector; 
import java.nio.channels.SocketChannel; 
import java.util.Iterator; 
import java.util.Set; 

public class Client { 
    public static void main(String args[]) throws Exception { 
     // Create client SocketChannel 
     SocketChannel client = SocketChannel.open(); 

     // nonblocking I/O 
     client.configureBlocking(false); 

     // Connection to host port 8000 
     client.connect(new java.net.InetSocketAddress("127.0.0.1", 8000)); 

     // Create selector 
     Selector selector = Selector.open(); 

     // Record to selector (OP_CONNECT type) 
     SelectionKey clientKey = client.register(selector, 
       SelectionKey.OP_CONNECT); 

     int counter = 0; 
     boolean chk = true; 

     // Waiting for the connection 
     while (selector.select(500) > 0 && chk) { 
      // Get keys 
      Set<SelectionKey> keys = selector.selectedKeys(); 
      Iterator<SelectionKey> i = keys.iterator(); 

      // For each key... 
      while (i.hasNext() && chk) { 
       SelectionKey key = (SelectionKey) i.next(); 

       // Remove the current key 
       i.remove(); 

       // Get the socket channel held by the key 
       SocketChannel channel = (SocketChannel) key.channel(); 

       // Attempt a connection 
       if (key.isConnectable()) { 

        // Connection OK 
        System.out.println("Server Found"); 

        // Close pendent connections 
        if (channel.isConnectionPending()) 
         channel.finishConnect(); 

        // Write continuously on the buffer 
        ByteBuffer buffer = null; 
        for (;chk;counter++) { 
         Thread.sleep(1000); 
         buffer = ByteBuffer.wrap(new String(" Client ").getBytes()); 
         channel.write(buffer); 
         buffer.clear(); 

         if (counter == 2) 
         { 
          chk = false; 
          client.close(); 
         } 
        } 

       } 
      } 
     } 
    } 
} 

任何人都可以解釋什麼是錯我的代碼? 在此先感謝。

回答

4

你大概從接受套接字渠道獲得的EOS-S絡繹不絕。你忽略了read()的結果。您至少必須檢查它是否爲-1,如果這樣關閉通道。

2

NIO套接字API是非阻塞的。選擇器返回準備好操作的鍵。如果沒有準備好的話,它會繼續循環。這是預期的行爲。

+0

感謝您的回答,但我還有一個問題:爲什麼在收到3條消息之前,它被封鎖了,之後​​呢,它是非阻塞的? – Leo 2012-03-16 15:43:04

+0

我回顧了你的回答「如果沒有任何東西準備好就會繼續循環」,我認爲你在這一點上是正確的,但是循環應該被'selector.select()'阻止,爲什麼它是不? – Leo 2012-03-17 02:40:26

+2

除非您的讀取失敗,否則無法檢測到對方已斷開連接。因此,選擇將始終返回可讀的選擇鍵,相信它已準備好閱讀。現在,您有責任檢測它是否有效,並在讀取失敗時取消密鑰。改變服務器端如下,你應該沒問題。 SocketChannel client =(SocketChannel)key.channel(); int BUFFER_SIZE = 1024; ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); int bytesread = client.read(buffer); if(bytesread == -1){key.cancel(); client.close();繼續; } – Drona 2012-03-17 06:11:36

-2

不堵,因爲

server.configureBlocking(false); 
在Server.main

()

+0

選擇(?不是答案。 – EJP 2012-03-17 03:42:18

相關問題