Java NIO sockets: the server doesn't receive the second message over the same socket

Mindaugas Varkalys :

I have simple Server and Client built using Java NIO sockets. The idea is that the client sends 5 to server and the server replies with 1. Then, the client sends 1 again using the same socket and the server should reply with 5 again.

However, the server does not receive the second message. Here is my implementation:

Server.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;

public class Server {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(4444));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            if (selector.select() > 0) {
                for (SelectionKey key : selector.selectedKeys()) {
                    if (key.isReadable()) {
                        SocketChannel clientChannel = (SocketChannel) key.channel();
                        ByteBuffer buffer = ByteBuffer.allocate(1);
                        clientChannel.read(buffer);
                        System.out.println("Received: " + buffer.array()[0]);
                        clientChannel.write(ByteBuffer.wrap(new byte[]{1}));
                        System.out.println("Replied: 1");
                    }
                    if (key.isAcceptable()) {
                        SocketChannel channel = serverChannel.accept();
                        if (channel != null) {
                            channel.configureBlocking(false);
                            channel.register(selector, SelectionKey.OP_READ);
                            System.out.println("Accepted");
                        }
                    }
                }
            }
        }
    }
}

Client.java

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class Client {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        SocketChannel sc = SocketChannel.open();
        sc.configureBlocking(false);
        sc.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 4444));
        sc.register(selector, SelectionKey.OP_CONNECT);

        while (true) {
            if (selector.select() > 0) {
                for (SelectionKey key : selector.selectedKeys()) {
                    SocketChannel channel = (SocketChannel) key.channel();
                    if (key.isConnectable()) {
                        while (channel.isConnectionPending()) {
                            channel.finishConnect();
                        }
                        key.interestOps(SelectionKey.OP_WRITE);
                        System.out.println("Connected");
                    }
                    if (key.isWritable()) {
                        channel.write(ByteBuffer.wrap(new byte[] { 5 }));
                        key.interestOps(SelectionKey.OP_READ);
                        System.out.println("Sending: 5");
                    }
                    if (key.isReadable()) {
                        ByteBuffer buffer = ByteBuffer.allocate(1);
                        channel.read(buffer);
                        System.out.println("Received: " + buffer.array()[0]);
                        key.interestOps(SelectionKey.OP_WRITE);
                    }
                }
            }
        }
    }
}

Server ouput

Accepted
Received: 5
Replied: 1

Client output

Connected
Sending: 5
Received: 1
Sending: 5
Mindaugas Varkalys :

I found a solution to my problem here: https://stackoverflow.com/a/9940133/4167198

select() returns the number of keys that have changed. So if a key was already ready before the select() call then it could return 0 but selectedKeys could be non-empty.

So checking if select() returns more than 0 is not necessary.

Server.java

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;

public class Server {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.bind(new InetSocketAddress(4444));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();
            for (SelectionKey key : selector.selectedKeys()) {
                if (key.isReadable()) {
                    SocketChannel clientChannel = (SocketChannel) key.channel();
                    ByteBuffer buffer = ByteBuffer.allocate(1);
                    clientChannel.read(buffer);
                    System.out.println("Received: " + buffer.array()[0]);
                    clientChannel.write(ByteBuffer.wrap(new byte[]{1}));
                    System.out.println("Replied: 1");
                }
                if (key.isAcceptable()) {
                    SocketChannel channel = serverChannel.accept();
                    if (channel != null) {
                        channel.configureBlocking(false);
                        channel.register(selector, SelectionKey.OP_READ);
                        System.out.println("Accepted");
                    }
                }
            }
        }
    }
}

Client.java

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;

public class Client {

    public static void main(String[] args) throws IOException {
        Selector selector = Selector.open();
        SocketChannel sc = SocketChannel.open();
        sc.configureBlocking(false);
        sc.connect(new InetSocketAddress(InetAddress.getByName("127.0.0.1"), 4444));
        sc.register(selector, SelectionKey.OP_CONNECT);

        while (true) {
            selector.select();
            for (SelectionKey key : selector.selectedKeys()) {
                SocketChannel channel = (SocketChannel) key.channel();
                if (key.isConnectable()) {
                    while (channel.isConnectionPending()) {
                        channel.finishConnect();
                    }
                    key.interestOps(SelectionKey.OP_WRITE);
                    System.out.println("Connected");
                }
                if (key.isWritable()) {
                    channel.write(ByteBuffer.wrap(new byte[] { 5 }));
                    key.interestOps(SelectionKey.OP_READ);
                    System.out.println("Sending: 5");
                }
                if (key.isReadable()) {
                    ByteBuffer buffer = ByteBuffer.allocate(1);
                    channel.read(buffer);
                    System.out.println("Received: " + buffer.array()[0]);
                    key.interestOps(SelectionKey.OP_WRITE);
                }
            }
        }
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=356572&siteId=1