在NIO阅读和写作的许多问题



我正在使用nio练习,并尝试与客户端和服务器端一起制作一个简单的应用程序。该应用程序应仅在从CLIEN到服务器的字节中发送消息,然后将其他消息作为响应发送。我的代码在这里。但是我有很多不同的问题。

有时从方法readMessage()线int bytesRead = socketChannel.read(byteBuffer);bytesRead = socketChannel.read(byteBuffer);行读取零字节的无尽序列并抛出OOM错误。

有时来自服务器的响应看起来像{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwAu003d"}

有时响应具有奇怪的尾巴: {"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwAu003d"}YQ11ZVwAu003d

服务器和Client都使用相同的方法来读取和写作。我从客户端{"class":"server.PasswordHashRequest","login":"admin"} 发送并期望{"class":"server.PasswordHashResponse","xoredHash":"RV5GX1JVAwADBEVZWwFGTAhZQ1FGX1tYQ11ZVwAu003d"}。使用相同的代码,几分钟后,我现在可以遇到一个问题,另一个问题。我尝试了我知道的任何东西。我是否设法在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();
}

写方法:

    public static void writeMessage(String message, SocketChannel channel) throws IOException {
    message += "rn";
    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();
}
  • 如果bytesRead <= 0
  • ,您的阅读方法应停止阅读
  • 构造字符串时应考虑缓冲区限制
  • 您的写入方法应停止尝试写作,如果write()返回零,然后(然后(注册OP_WRITE的频道,并且仅在开火时继续写作。

在此处查看许多类似的问题。

最新更新