0

I've written minimal example, but it's still too long, so let me know I should post the link to Pastebin instead.

Server:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

public class Srv {
    static final int    PORT = 9001;
    static final String HOST = "127.0.0.1";
    public static void runInstance() {
        try (AsynchronousServerSocketChannel asynchronousServerSocketChannel =
                     AsynchronousServerSocketChannel.open()) {
            if (asynchronousServerSocketChannel.isOpen()) {
                asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024);
                asynchronousServerSocketChannel.setOption(StandardSocketOptions.SO_REUSEADDR, true);
                asynchronousServerSocketChannel.bind(new InetSocketAddress(HOST, PORT));
                System.out.println(String.format("Launched master on %s:%d", HOST, PORT));

                asynchronousServerSocketChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
                    @Override
                    public void completed(AsynchronousSocketChannel result, Void attachment) {
                        asynchronousServerSocketChannel.accept(null, this);
                        try {
                            result.read(ByteBuffer.allocate(1024));
                            System.out.println("Conn from:" + result.getRemoteAddress());
                        } catch (Exception exn) {
                            exn.printStackTrace();
                        } finally {
                            try {
                                result.close();
                            } catch (IOException exn) {
                                exn.printStackTrace();
                            }
                        }
                    }
                    @Override
                    public void failed(Throwable exn, Void attachment) {
                        asynchronousServerSocketChannel.accept(null, this);
                        throw new UnsupportedOperationException("can't accept");
                    }
                });
                System.in.read();
            } else {
                System.out.println("The asynchronous server-socket channel cannot be opened");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

}

Client:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

import static java.lang.Thread.sleep;

public class Wrk {
    static final int    PORT = 9001;
    static final String HOST = "127.0.0.1";
    public static void runInstance() throws InterruptedException {
        sleep(1000); //HERE
        try(AsynchronousSocketChannel asynchronousSocketChannel = AsynchronousSocketChannel.open()) {
            if (asynchronousSocketChannel.isOpen()) {
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_RCVBUF, 1024);
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_SNDBUF, 1024);
                asynchronousSocketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
                asynchronousSocketChannel.connect(new InetSocketAddress(HOST, PORT), null,
                    new CompletionHandler<Void, Void>() {
                        @Override
                        public void completed(Void result, Void attachment) {
                            try {
                                System.out.println("Connected to: " + HOST + PORT);
                                asynchronousSocketChannel.read(ByteBuffer.allocate(1024)).get();
                            } catch (Exception exn) {
                                exn.printStackTrace();
                            } finally {
                                try {
                                    asynchronousSocketChannel.close();
                                } catch (IOException exn) {
                                    exn.printStackTrace();
                                }
                            }
                        }

                        @Override
                        public void failed(Throwable throwable, Void o) {
                            System.out.println("Connection cannot be established");
                        }
                    });
                sleep(1000); //AND HERE
            } else {
                System.out.println("The asynchronous socket channel cannot be opened");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Boilerplate to run:

public class Main {
    public static void main(String[] args) throws InterruptedException {
        Thread srv = new Thread(new Runnable() {
            @Override
            public void run() {
                Srv.runInstance();
            }
        });
        srv.start();
        Thread wrk1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Wrk.runInstance();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
        wrk1.start();
    }
}

So, if I have the code like this, it gives me the following output:

Launched master on 127.0.0.1:9001
Connected to: 127.0.0.1 9001
Conn from:/127.0.0.1:50415

But if I remove those sleep()s in Srv.runInstance(), I get:

Connection cannot be established
Launched master on 127.0.0.1:9001
Conn from:/127.0.0.1:50438

So, does that mean that client connects to server, but server refuses? I don't clearly understand what happens here and documentation is rather poor, so I don't know where to look for solutions.

tkroman
  • 4,811
  • 1
  • 26
  • 46
  • When you get an exception, including one passed to a failed() method, don't just print out a message of your own devising. Print the message that comes with the exception. That will almost certainly answer your question. NB your isOpen() tests are both pointless. The channel cannot but be open at the points you are testing it, otherwise an exception would have been thrown. – user207421 Oct 06 '13 at 20:36
  • @EJP, that's a reworked example from the book, so I didn't change any architecture except in the places I ask about. Anyway, the exceptions are `ClosedChannelException` that don't give much to think about. – tkroman Oct 06 '13 at 21:00
  • On the contrary, it answers your question, as I predicted it would. ClosedChannelException means that *you* closed the channel and then continued to use it. Your first sentence is meaningless to me. There is no 'architecture' involved in printing incorrect messages, just poor programming practice. – user207421 Oct 06 '13 at 21:13
  • 'architecture' part is about `isOpen()`-related issues. Could you please be more elaborate on *me* closing the channel? I'm sorry if my question isn't that much correct, but I'm really interested in solving the problem. – tkroman Oct 06 '13 at 21:16
  • Coding isn't architecture. I don't know what else you expect me to say about you closing the channel. The application *in this JVM* has closed *this channel.*. Not the connection, not the peer. So you have a bug somewhere. – user207421 Oct 06 '13 at 23:52
  • Yeah... That's the point and that's the purpose of SO, isn't it? – tkroman Oct 07 '13 at 05:21
  • You have a bug somewhere with premature closing of the channel. How many times do I have to say it? – user207421 Oct 07 '13 at 22:12
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/38748/discussion-between-cdshines-and-ejp) – tkroman Oct 07 '13 at 22:34

1 Answers1

1

The only sleep I see in the posted code is in Wrk.runInstance. However, the order of your output makes it pretty clear what is going on. Your working is trying to connect to the server before it has fully initialized. As you can see in your output, the "Connection message" is before the "Launched master".

The server takes a bit of time to start, so without the sleep, your client is trying to connect to something which is not yet there.

Aurand
  • 5,487
  • 1
  • 25
  • 35
  • But why does it need the sleep *after* the `runInstance()`? If i uncomment the first `sleep()` and comment out the one *at the end of* `runInstance()` , that behaviour is still observable. The question is basically about the second one, because I clearly understand the purpose of the first on - to give some time for server warm-up. – tkroman Oct 06 '13 at 17:13