2017-02-05 28 views
1

這是的chargen服務器的一個例子,我在書中發現,我正在讀:如何使用NIO套接字只寫一次或「在某些命令上」?

import java.nio.*; 
import java.nio.channels.*; 
import java.net.*; 
import java.util.*; 
import java.io.IOException; 

public class ChargenServer { 

    public static int DEFAULT_PORT = 19; 

    public static void main(String[] args) { 

    int port; 
    try { 
     port = Integer.parseInt(args[0]); 
    } 
    catch (Exception ex) { 
     port = DEFAULT_PORT; 
    } 
    System.out.println("Listening for connections on port " + port); 

    byte[] rotation = new byte[95*2]; 
    for (byte i = ' '; i <= '~'; i++) { 
     rotation[i-' '] = i; 
     rotation[i+95-' '] = i; 
    } 

    ServerSocketChannel serverChannel; 
    Selector selector; 
    try { 
     serverChannel = ServerSocketChannel.open(); 
     ServerSocket ss = serverChannel.socket(); 
     InetSocketAddress address = new InetSocketAddress(port); 
     ss.bind(address); 
     serverChannel.configureBlocking(false); 
     selector = Selector.open(); 
     serverChannel.register(selector, SelectionKey.OP_ACCEPT); 
    } 
    catch (IOException ex) { 
     ex.printStackTrace(); 
     return; 
    } 

    while (true) { 

     try { 
     selector.select(); 
     } 
     catch (IOException ex) { 
     ex.printStackTrace(); 
     break; 
     } 

     Set readyKeys = selector.selectedKeys(); 
     Iterator iterator = readyKeys.iterator(); 
     while (iterator.hasNext()) { 

     SelectionKey key = (SelectionKey) iterator.next(); 
     iterator.remove(); 
     try { 
      if (key.isAcceptable()) { 
      ServerSocketChannel server = (ServerSocketChannel) key.channel(); 
      SocketChannel client = server.accept(); 
      System.out.println("Accepted connection from " + client); 
      client.configureBlocking(false); 
      SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE); 
      ByteBuffer buffer = ByteBuffer.allocate(74); 
      buffer.put(rotation, 0, 72); 
      buffer.put((byte) '\r'); 
      buffer.put((byte) '\n'); 
      buffer.flip(); 
      key2.attach(buffer); 
      } 
      else if (key.isWritable()) { 
      SocketChannel client = (SocketChannel) key.channel(); 
      ByteBuffer buffer = (ByteBuffer) key.attachment(); 
      if (!buffer.hasRemaining()) { 
       // Refill the buffer with the next line 
       buffer.rewind(); 
       // Get the old first character 
       int first = buffer.get(); 
       // Get ready to change the data in the buffer 
       buffer.rewind(); 
       // Find the new first characters position in rotation 
       int position = first - ' ' + 1; 
       // copy the data from rotation into the buffer 
       buffer.put(rotation, position, 72); 
       // Store a line break at the end of the buffer 
       buffer.put((byte) '\r'); 
       buffer.put((byte) '\n'); 
       // Prepare the buffer for writing 
       buffer.flip(); 
      } 
      client.write(buffer); 
      } 
     } 
     catch (IOException ex) { 
      key.cancel(); 
      try { 
      key.channel().close(); 
      } 
      catch (IOException cex) {} 
     } 

     } 

    } 

    } 

} 

一旦客戶端連接到服務器時,它繼續發送字符流給客戶端,並不會停止。

我很好奇,如果我想發送緩衝一次,仍然保持服務器連接到客戶端。我該怎麼辦?

回答

1

套接字通道幾乎都是可寫的。當你有一個零長度的寫入時,你應該只在OP_WRITE上選擇。如果你有一些東西要寫,就寫下來,然後檢查返回值。

+0

因此,使用'OP_WRITE'是爲了始終保持寫入循環? – user963241

+0

我不明白你。 OP_WRITE的使用是告訴你什麼時候套接字在非常罕見的情況之一之後變成可寫的,如''write()'返回零信號。 – EJP

+0

我明白了。如果正常的'write()'失敗,那麼我應該註冊OP_WRITE並讓它繼續嘗試寫入,直到成功,然後在'key.isWriteable()'內部取消註冊? – user963241

相關問題