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