2017-02-05 11 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

相关问题