2017-06-03 2 views
1

Je m'entraîne avec NIO et essaie de faire une application simple avec les côtés client et serveur. Cette application devrait juste envoyer un message en octets de clien au serveur et obtenir un autre message en guise de réponse. Mon code est ici. Mais j'ai beaucoup de problèmes différents.Beaucoup de problèmes avec la lecture et l'écriture dans NIO

Parfois, les lignes int bytesRead = socketChannel.read(byteBuffer); ou bytesRead = socketChannel.read(byteBuffer); de la méthode readMessage() lisent une séquence sans fin de zéro octet et déclenchent une erreur d'OOM. Parfois la réponse du serveur ressemble à that au lieu de {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}

Parfois, la réponse a cette queue bizarre comme: {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}YQ11ZVwA\u003d

serveur et l'utilisation des mêmes méthodes cliend pour la lecture et l'écriture. J'envoie du client {"class":"server.PasswordHashRequest","login":"admin"} et attendre {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}. Avec le même code, je peux obtenir un numéro maintenant et un autre numéro quelques minutes plus tard. J'ai essayé tout ce que je sais. Ai-je réussi à obtenir une erreur de segmentation en Java?

code côté client:

@Test 
public void main() throws Exception { 
    System.out.println("Opening socket"); 
    InetSocketAddress socketAddress = new InetSocketAddress("localhost", 9090); 
    SocketChannel socketChannel = SocketChannel.open(); 
    socketChannel.configureBlocking(false); 
    Selector selector = Selector.open(); 
    socketChannel.register(selector, OP_CONNECT); 
    socketChannel.connect(socketAddress); 
    PasswordHashRequest request = new PasswordHashRequest("admin"); 
    System.out.println("Socket open"); 
    while (true) { 
     System.out.println("Client selector awoken"); 
     selector.select(); 
     for (SelectionKey selectionKey : selector.selectedKeys()) { 
      if (selectionKey.isConnectable()) { 
       socketChannel.finishConnect(); 
       selectionKey.interestOps(OP_WRITE); 
      } else if (selectionKey.isReadable()) { 
       String response = ServerManager.readMessage((SocketChannel) selectionKey.channel()); 
       System.out.println(response); 
       server.interrupt(); 
      } else if (selectionKey.isWritable()) { 
       ServerManager.sendMessage(request, (SocketChannel) selectionKey.channel()); 
       System.out.println("Request sent"); 
       selectionKey.interestOps(OP_READ); 
      } 
     } 
    } 
} 

code côté serveur:

public void run() { 
    System.out.println("Main thread started"); 
    while (true) { 
     try { 
      // Get ready channels 
      int readyChannels = selector.select(); 
      if (readyChannels == 0) { continue; } 

      Set<SelectionKey> selectedKeys = selector.selectedKeys(); 
      Iterator<SelectionKey> keyIterator = selectedKeys.iterator(); 

      // Handle Events 
      while (keyIterator.hasNext()) { 
       SelectionKey key = keyIterator.next(); 

       // New Client 
       if (key.isAcceptable()) { 
        System.out.println("New Client Accepted"); 
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel(); 
        serverSocketChannel.configureBlocking(false); 

        SocketChannel socketChannel = serverSocketChannel.accept(); 
        socketChannel.configureBlocking(false); 
        SelectionKey clientKey = socketChannel.register(selector, SelectionKey.OP_READ); 
        Random randomInt = new Random(System.currentTimeMillis()); 
        clientKey.attach(randomInt.nextInt(Integer.SIZE - 1)); 
       } 
       // Client has sent data 
       else if (key.isReadable()) { 
        handleInput(key); 
       } 

       keyIterator.remove(); 
      } 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 

Méthode de lecture:

public static String readMessage(SocketChannel socketChannel) throws IOException { 
    ByteBuffer byteBuffer = ByteBuffer.allocate(16); 
    byteBuffer.clear(); 
    StringBuilder stringBuilder = new StringBuilder(); 
    int bytesRead = socketChannel.read(byteBuffer); 
    while (bytesRead != -1) { 
     byteBuffer.flip(); 
     String byteString = new String(byteBuffer.array(), Charset.forName("UTF-8")); 
     stringBuilder.append(byteString); 
     byteBuffer.clear(); 
     bytesRead = socketChannel.read(byteBuffer); 
    } 
    socketChannel.shutdownInput(); 
    return stringBuilder.toString(); 
} 

méthode Write:

public static void writeMessage(String message, SocketChannel channel) throws IOException { 
    message += "\r\n"; 
    System.out.println(message); 
    int bufferLength = 16; 
    byte[] responseBytes = message.getBytes(); 
    int offset = 0; 
    ByteBuffer buf = ByteBuffer.allocate(bufferLength); 
    while (responseBytes.length > offset) { 
     buf.clear(); 
     int div = responseBytes.length - offset; 
     if (div >= bufferLength) { 
      buf.put(responseBytes, offset, bufferLength); 
     } else { 
      buf.put(responseBytes, offset, div); 
     } 
     buf.flip(); 
     channel.write(buf); 
     offset += bufferLength; 
    } 
    channel.shutdownOutput(); 
} 

Répondre

2
  • Votre méthode de lecture devrait arrêter de lire si bytesRead <= 0
  • Il faut tenir compte de la limite de mémoire tampon lors de la construction de la chaîne
  • Votre méthode d'écriture devrait cesser d'essayer d'écriture si write() renvoie zéro, puis (et seulement ensuite) registre le canal pour OP_WRITE, et continue seulement d'écrire quand il se déclenche.

Voir beaucoup de questions similaires ici sur tout cela.

+0

Merci beaucoup, je vais essayer aujourd'hui. –