2017-02-05 1 views
1

est un exemple de serveur chargen j'ai trouvé dans le livre que je lisais:Comment écrire une seule fois ou "sur une commande" en utilisant des sockets NIO? Ce

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) {} 
     } 

     } 

    } 

    } 

} 

Une fois que le client est connecté au serveur, il continue à envoyer un flux de caractères au client et ne s'arrête pas.

Je suis curieux si je veux envoyer le tampon une fois et toujours garder le serveur connecté au client. Que devrais-je faire?

Répondre

1

Les canaux de socket sont presque toujours accessibles en écriture. Vous ne devez sélectionner OP_WRITE que si vous avez déjà écrit une longueur zéro. Si vous avez quelque chose à écrire, écrivez-le, puis vérifiez la valeur de retour.

+0

Donc l'utilisation de 'OP_WRITE' est de toujours écrire en boucle? – user963241

+0

Je ne vous comprends pas. L'utilisation de OP_WRITE est de vous dire quand le socket est devenu inscriptible après l'une des rares occasions où il ne l'est pas, comme signalé par un retour à zéro de 'write()'. – EJP

+0

Je vois. Si normal 'write()' échoue alors je devrais enregistrer OP_WRITE et le laisser continuer à écrire jusqu'à ce qu'il réussisse puis désenregistrer dans 'key.isWriteable()'? – user963241