I'm trying to connect to a remote server and send a login message in my Thread:
#Override
public void run() {
try {
address = new InetSocketAddress(host, port);
incomingMessageSelector = Selector.open();
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(address);
socketChannel.register(incomingMessageSelector, SelectionKey.OP_READ);
serverManager.loginToServer();
}
}
the loginServer() is a method which send a message to ther server but i keep getting an:
java.nio.channels.NotYetConnectedException
how can i check and wait for connection before sending this loginServer() method?
If you're connecting in non-blocking mode you should:
register the channel for OP_CONNECT
when it fires call finishConnect()
if that returns true, deregister OP_CONNECT and register OP_READ or OP_WRITE depending on what you want to do next
if it returns false, do nothing, keep selecting
if either connect() or finishConnect() throws an exception, close the channel and try again or forget about it or tell the user or whatever is appropriate.
If you don't want to do anything until the channel connects, do the connect in blocking mode and go into non-blocking mode when the connect succeeds.
i've found an answer.. i should use:
socketChannel = SocketChannel.open(address);
socketChannel.configureBlocking(false);
while (!socketChannel.finishConnect());
//my code after connection
because the NIO is in not blocking mode we have to wait until it finish its connection
Related
When a select call on a write channel blocks, is it waiting on the server to respond? Or is it just waiting for the network to respond.
SocketChannel sChannel;
Selector selector;
SelectionKey selectionKey;
...
selector = Selector.open();
selectionKey = sChannel.register(selector, 0);
selectionKey.interestOps(SelectionKey.OP_WRITE);
selector.select(timeout*1000);
When a select call on a write channel blocks, is it waiting on the server to respond?
When a select() call on a channel registered only for OP_WRITE, like your example, blocks, it is waiting for space in the socket send buffer, which in turn is waiting for space in the receiver's socket receive buffer, which in turn is waiting for the peer to read.
I want to determine port whether open.
InetSocketAddress address = new InetSocketAddress("www.google.com", 80);
Selector selector = Selector.open();
SocketChannel socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.connect(address);
socketChannel.register(selector, SelectionKey.OP_WRITE);
int result = selector.select();
System.out.println(result);
If the port is not open, think I look the same it return 0,
but when the port is open,it also return 0,I expect it can return 1.
It's because you're selecting for the wrong event. You should have registered the channel for OP_CONNECT. Then, when you get it, call finishConnect(), and if it returns true deregister OP_CONNECT and register whatever event you're interested in next, i.e. OP_READ or OP_WRITE.
Note that if finishConnect() returns false you should just keep selecting, and if it throws an exception the connection has failed and you should close the channel.
If you want to avoid all this complication it is usually simpler to do the connect while still in blocking mode, and then put the channel into non-blocking mode and select.
Although there is really very little point in using NIO in a client at all.
See here for a fuller version of this answer.
What does the server.accept() method return when no new socket is formed, i.e., when no new connection is made? Is it possible to go to next line of code while sever.accept() is waiting for a new connection?
If you want to do something while the server is waiting for a connection you can use multiple threads. In a single-threaded application you cannot call a function and continue with your work without waiting it to return: either you are waiting for the server to accept a connection, or you are doing other computations.
A possible alternative to threads is setting the SO_TIMEOUT socket option on the server socket. This makes the call to accept throw an exception if a connection is not received within the timeout, allowing you to go to the next line.
For example:
ServerSocket ss = new ServerSocket(8989);
ss.setSoTimeout(10000); // 10 seconds
Socket clientSocket;
try {
clientSocket = ss.accept();
// process connection from client
} catch (SocketTimeoutException ste) {
// connection was not received,
// do something else
}
Another alternative is using non-blocking IO and the Selector class. Here's an example of a non-blocking socket server written this way.
No. server.accept() is a blocking method and it will wait.
From the javadoc
Listens for a connection to be made to this socket and accepts it. The
method blocks until a connection is made.
In writing some test code I have found that Selector.select() can return without Selector.selectedKeys() containing any keys to process. This is happening in a tight loop when I register an accept()ed channel with
SelectionKey.OP_READ | SelectionKey.OP_CONNECT
as the operations of interest.
According to the docs, select() should return when:
1) There are channels that can be acted upon.
2) You explicitly call Selector.wakeup() - no keys are selected.
3) You explicitly Thread.interrupt() the thread doing the select() - no keys are selected.
If I get no keys after the select() I must be in cases (2) and (3). However, my code is not calling wakeup() or interrupt() to initiate these returns.
Any ideas as to what is causing this behaviour?
Short answer: remove OP_CONNECT from the list of operations you are interested in for the accepted connection -- an accepted connection is already connected.
I managed to reproduce the issue, which might be exactly what's happening to you:
import java.net.*;
import java.nio.channels.*;
public class MyNioServer {
public static void main(String[] params) throws Exception {
final ServerSocketChannel serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking(true);
serverChannel.socket().bind(new InetSocketAddress("localhost", 12345));
System.out.println("Listening for incoming connections");
final SocketChannel clientChannel = serverChannel.accept();
System.out.println("Accepted connection: " + clientChannel);
final Selector selector = Selector.open();
clientChannel.configureBlocking(false);
final SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_CONNECT);
System.out.println("Selecting...");
System.out.println(selector.select());
System.out.println(selector.selectedKeys().size());
System.out.println(clientKey.readyOps());
}
}
After the above server receives a connection, the very first select() on the connection exits without blocking and there are no keys with ready operations. I don't know why Java behaves in this way, but it appears many people get bitten by this behavior.
The outcome is the same on Sun's JVM 1.5.0_06 on Windows XP as well as Sun's JVM 1.5.0_05 and 1.4.2_04 on Linux 2.6.
The reason is that OP_CONNECT and OP_WRITE are the same thing under the hood, so you should never be registered for both simultaneously (ditto OP_ACCEPT and OP_READ), and you should never be registered for OP_CONNECT at all when the channel is already connected, as it is in this case, having been accepted.
And OP_WRITE is almost always ready, except when the socket send buffer in e kernel is full, so you should only register for that after you get a zero length write. So by registering the already connected channel for OP_CONNECT, you were really registering for OP_WRITE, which was ready, so select() got triggered.
You should use OP_CONNECT when you connect to server, not when you are listening for incoming connections. Also make sure to configureBlocking before connect:
Selector selector = Selector.open();
SocketChannel serverChannel = SocketChannel.open(StandardProtocolFamily.INET);
serverChannel.configureBlocking(false);
serverChannel.connect(new InetSocketAddress("localhost", 5454));
serverChannel.register(selector, SelectionKey.OP_CONNECT);
// event process cycle
{
int count = selector.select();
for (SelectionKey key : selector.selectedKeys()) {
log.info(" {}", key.readyOps());
if (key.isConnectable()) {
log.info("Connection is ready");
key.interestOps(SelectionKey.OP_READ);
}
if (key.isReadable()) {
// read data here
}
}
When I code like this:
ServerSocketChannel ssc = ServerSocketChannel.open();
InetSocketAddress sa = new InetSocketAddress("localhost",8888);
ssc.socket().bind(sa);
ssc.configureBlocking(false);
ssc.socket().accept();
the ServerSocket.accept() method throws java.nio.channels.IllegalBlockingModeException. Why can't I call accept(), even though I set blocking to false?
The problem is that you are calling ssc.socket().accept(), not ssc.accept(). If you change the last line to ssc.accept() then it will work as expected, which is to return a SocketChannel if one is waiting or null if not.
Because that's what javadoc for serversocket.accept() says?
IllegalBlockingModeException - if this socket has an associated channel, and the channel is in non-blocking mode.
The Javadoc specifically states that ServerSocketChannel.accept():
Accepts a connection made to this channel's socket.
If this channel is in non-blocking mode then this method will immediately
return null if there are no pending connections. Otherwise it will block
indefinitely until a new connection is available or an I/O error occurs.
The general idea is:
If you want to block while waiting for incoming connections, you leave the server socket in blocking mode. If you're writing a server that has nothing to do until a connection actually comes in, then blocking mode is what you want.
If you want to do other things, and periodically check to see whether there's a pending connection, you want non-blocking mode.
Blocking mode is the default for a reason: Most servers don't want to poll their accepting socket for incoming connections.