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.
Related
I'm trying to write an emulator for a single-threaded physical product. It accepts one long-lived connection and any other connections get a single error message (in the same thread).
I know I can use java.net with two threads:
Thread 1 - start ServerSocket on port XXXX and wait for accept(). For the first connection create a Socket and Thread #2, and for other connections produce an error message.
Thread 2 - process the Socket IO.
But how can I do it with one thread, so it behaves more like the physical product (ie. repeatedly attempting connections would starve the thread from dealing with the first connection)?
Trying not to use third-party libraries, but can do if that's the only option.
Thanks!
Unfortunately the common java.net.ServerSocket as well as the java.nio.channels.ServerSocketChannel only feature a blocking method to accept incoming connections. However the java.nio package features many other classes and methods to handle I/O-Operations in a single thread by multiplexing the opened channels.
This approach would still enforce a dedicated Thread for the accepting ServerSocketChannel but you could handle every accepted connection in a single thread.
In comparison the ServerSocket approach needs one new thread for each new connection.
Imgaine you connect 100 clients using a ServerSocket then you will end up with 101 thread. With a ServerSocketChannel you could end up using only 2 thread.
Still programming is often about a tradeoff between complexity/flexibility and performance. So keep that in mind.
A possible solution I could think of could look like this:
public static void main( String[] args ) throws IOException
{
int portNr = 8080;
ExecutorService es = Executors.newSingleThreadExecutor();
ChannelHandler ch = new ChannelHandler();
es.execute( ch );
// Starting server:
ServerSocketChannel serv = ServerSocketChannel.open();
// Bind socket to Port
serv.socket().bind(new InetSocketAddress(portNr));
while( serverAlive )
{
ch.addChannel(serv.accept());
}
serv.close();
}
How you actually process the new added SocketChannel depends on your application. And so does the ChannelHandler#addChannel method.
It seems like you should accept the single connection and then close the ServerSocket. Any future connect attempts will then get a connection refusal. When the long-lived connection ends, create a new ServerSocket, accept one more connection, ... Rinse and repeat.
EDIT If you have to deliver an error message as per your comment below, you have to accept the connection to send it over, and if you have to do I/O and accepting all in one thread you have to use java.nio.channels.ServerSocketChannel/SocketChannel, non-blocking mode, and a Selector.
Using a ServerSocket with one Thread is not a good idea at all. WHY?
you know socket.accept() waits till the next client connects, so the Thread is blocked and if you only have one Thread your whole Programm is blocked till a Client connects.
May you explain why you try to do it single threaded?
There is the connecting timeout value passed to connect method, and there is the reading timeout set using setSoTimeout method. I was wondering why there is no method to set the "writing timeout"? I think there is the writing timeout concept in the TCP Protocol.
It wouldn't be much use.
In general TCP sending is asynchronous to the application. All that send() does is put the data into the socket send buffer. It then returns, while the send buffer is emptied to the network asynchronously. So there is nothing to timeout. And the absence of a timeout does not denote that the data has been sent to the peer.
send() blocks while the send buffer is full, and it would be possible to implement a timeout on that, and indeed you can do that yourself in non-blocking mode with select(), but the problem is that what timed out could be either the current send or a prior one. So delivering a timeout would be rather confusing. Instead what is delivered when all the TCP send timers time out internally is a connection reset.
I think there is the writing timeout concept in the TCP Protocol.
There is indeed, but that's at the level where TCP is asynchronously emptying the socket send buffer. It isn't under application control.
you can first try to connect...if connect fails catch exception
InetSocketAddress sockAdr = new InetSocketAddress(serveradres, 2222);
Socket newsok = new Socket();
int timeout = 2000;
newsok.connect(sockAdr, timeout);
Is there a way to check for incoming connections to ServerSocket, so my server would not stop when waiting for someone to connect.
I need something like
try {
if (server.thereisarequest()) {
Socket socket = server.accept();
}
}
Are you sure you want this? Having the code presented, only one thread is waiting. Run another threads which handle accepted connections so that your server doesn't stop.
You can also use java non-blocking asynchronous I/O (nio and nio2), but in the background there is a thread on duty anyway.
Keep it simple... use an infinite while loop to make server look for the incoming request... thats how most of the servers works..
while (true) {
incoming = s.accept(); // incoming is of type Socket.
}
You can create a new thread to accept connections.
Then you have 2 choices:
Process the socket in a new thread
Put the sockets in a queue (ConcurrentLinkedQueue) and check it queue from you main thread.
im trying to implement a client app with an asynchronous connection. i want to know if i can reuse a SocketChannel object after it has failed to connect to a server.
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(false);
InetSocketAddress addr = new InetSocketAddress(host, port);
SelectionKey key = channel.register(select, SelectionKey.OP_READ, connection);
channel.connect(addr);
after this is the select loop, my socket eventually gets selected because the connection failed. i would like to queue another connection attempt on that channel, and nothing i do seems to do it. the channel.isConnectionPending() method always returns true (even if i try to finishConnect)
is the only solution do get rid of this SocketChannel and create a new one?
Sun has released the Java 6.0 sources under the GPL. "Read the source Luke"
And my reading of the code is that you cannot call connect a second time.
Hmmm... I'm no NIO expert but something looks fishy. You are registering for OP_ACCEPT, which occurs when a listening channel receives an incoming connection -- however, you're using the channel for an outgoing connection.
You should post more of the code, including the select loop.
Try it and see?
I'm not 100% sure, but I suspect you can once finishConnect has been called and returned or an exception from it thrown it may be ok.
Put a try/catch block around the connect and when the exception is caught you may be safe to call the channel.connect method again.
If it doesn't work then the answer is probably no.
I have a listening port on my server that I'm connecting to using a Java class and the Socket interface, i.e.
Socket mySocket = new Socket(host,port);
I then grab an OutputStream, decorate with a PrintWriter in autoflush mode and I'm laughing - except if the listening port closes. Then I get
tcp4 0 0 *.9999 *.* LISTEN
tcp 0 0 127.0.0.1.45737 127.0.0.1.9999 CLOSE_WAIT
and I can't seem to detect the problem in the program - I've tried using the isConnected() method on the socket but it doesn't seem to know that the connection is closed.
I want to be aware of the problem the next time I try and write to the Socket so that I can try and reconnect and report the issue.
Any advice please?
Thanks all
Set a short timeout?
Does isOutputShutdown() not get you what you want?
You could always build a SocketWatcher class that spins up in its own Thread and repeatedly tries to write empty strings to the Socket until that raises a SocketClosedException.
The only reliable way to detect a broken connection in TCP is to write to it, which will eventually cause a 'connection reset' IOException. However due to buffering it won't happen on the first write after the disconnection,p but on a subsequent write. You can't do anything about this.
Set a different thread to reading from the socket. It will block until the socket is closed, and then an exception will be thrown. Catch that exception to detect the close immediately.