2017-06-03 6 views
1

私はNIOで練習しており、クライアント側とサーバー側で簡単なアプリケーションを作成しようとしています。このアプリはちょうどクライエンからサーバーにメッセージをバイト単位で送信し、応答として他のメッセージを取得する必要があります。私のコードはここにあります。しかし、私にはさまざまな問題があります。NIOでの読み書きに関する多くの問題

時には、readMessage()メソッドからのint bytesRead = socketChannel.read(byteBuffer);またはbytesRead = socketChannel.read(byteBuffer);の行は、ゼロバイトの無限シーケンスを読み取り、OOMエラーをスローします。

{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}ではなく、サーバーからの応答がthatのように表示されることがあります。

時々応答は、このような奇妙な尾を持っている:両方のサーバー{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}YQ11ZVwA\u003d

と読み書き用に同じ方法を使用しcliend。 私はクライアント{"class":"server.PasswordHashRequest","login":"admin"} から送って、{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwA\u003d"}と期待しています。 同じコードを使用すると、今すぐ問題が発生し、数分後に問題が発生する可能性があります。 私は知っているものを試しました。私はJavaでsegfaultを取得できましたか?

クライアント側コード:

@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); 
      } 
     } 
    } 
} 

サーバー側のコード:

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(); 
     } 
    } 
} 

読む方法:

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(); 
} 

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(); 
} 

答えて

2
文字列
  • あなたの書き込み方法を構築するときには、バッファ制限を考慮すべきであるbytesRead <= 0
  • 場合あなたのreadメソッドがwrite()リターンがゼロの場合、書き込みをしようと停止してから、(だけにして)登録する必要があります読むのを止めなければならない
    • OP_WRITEのためのチャンネル。起動時にのみ書き込みを続けます。

    ここで多くの類似の質問があります。

  • +0

    ありがとう、私は今日それを試してみます。 –

    関連する問題