Search code examples
javaandroidselectornio

Java TCP server NIO with Selector in Android


I'm developing an app in android that will act as a server, this is, there will be an tablet that will be the "server" and there will be other tablets that will connect to the "server". I'm trying to use the java NIO with a selector, to save on threads. But my problem is, I have the java code running in a thread in android, but when the thread runs it don't happen nothing. On the client side it gives and exception of Connection Refused. The code is running in a java application, but in android not.

I also have the internet permission.

The java selector:

Thread t = new Thread(new Runnable() {

    private Selector            selector;
    private ServerSocketChannel sChan;
    private List<SocketChannel> sockets;

    public void run() {

        try {
            selector = SelectorProvider.provider().openSelector();
            sChan = ServerSocketChannel.open();
            InetSocketAddress iaddr = new InetSocketAddress(InetAddress.getLocalHost(), 8000);

            sChan.configureBlocking(false);
            sChan.socket().bind(iaddr);

            System.out.println("Running on port:" + sChan.socket().getLocalPort());

            sChan.register(selector, SelectionKey.OP_ACCEPT);
            sockets = new LinkedList<SocketChannel>();

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

        Iterator<SelectionKey> it;

        try {
            while (true) {
                selector.select();

                it = selector.selectedKeys().iterator();
                while (it.hasNext()) {
                    SelectionKey key = it.next();

                    it.remove();
                    if (!key.isValid()) {
                        continue;
                    }

                    // Finish connection in case of an error
                    if (key.isConnectable()) {
                        SocketChannel ssc = (SocketChannel) key.channel();
                        if (ssc.isConnectionPending()) {
                            ssc.finishConnect();
                        }
                    }

                    if (key.isAcceptable()) {
                        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
                        SocketChannel newClient = ssc.accept();

                        newClient.configureBlocking(false);
                        newClient.register(selector, SelectionKey.OP_READ);
                        sockets.add(newClient);

                        System.out.println("new client: " + newClient.socket().getInetAddress().getHostAddress());
                    }

                    if (key.isReadable()) {
                        SocketChannel sc = (SocketChannel) key.channel();
                        ByteBuffer data = ByteBuffer.allocate(sc.socket().getSendBufferSize());

                        System.out.println("new message: " + sc.socket().getInetAddress().getHostAddress());

                        if (sc.read(data) == -1) {
                            continue;
                        }

                        data.flip();

                        Teste m = (Teste) UdpUtil.byteToMessage(data.array());

                        System.out.println("message: " + m);
                        System.out.println("\n\n" + m.cenas);
                        sc.close();
                    }
                }
            }
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }
});
t.start();

And the Client application:

InetSocketAddress isa = new InetSocketAddress(InetAddress.getByName("192.168.2.102"), 8000);

    SocketChannel sc = null;

    try {

        // Connect
        sc = SocketChannel.open();
        sc.connect(isa);

        // Read the time from the remote host. For simplicity we assume
        // that the time comes back to us in a single packet, so that we
        // only need to read once.

        byte[] message = UdpUtil.messageToByteMessage(new messages.Teste("hello there"));

        ByteBuffer buf = ByteBuffer.wrap(message);
        sc.write(buf);
    }
    finally {
        // Make sure we close the channel (and hence the socket)
        if (sc != null) {
            sc.close();
        }
}

Note: the Teste class its just an class that will be used as the message between the androids.

I had even tried this code and all went well, but with the selector not. I hope that I made my self clear on what the problem is.

Thanks in advance :)


Solution

  • Remove the first argument to new InetSocketAddress(), the one you use for binding the ServerSocketChannel. At present you are only binding to 127.0.0.1, which cannot be seen from other hosts. By omitting the argument you are binding to 0.0.0.0, which means 'listen at all interfaces'.