Code for an echo server using a single threaded java I/O
public static void main(String[] args) throws Exception {
// create socket
int port = 4444;
ServerSocket serverSocket = new ServerSocket(port);
System.err.println("Started server on port " + port);
try {
// repeatedly wait for connections, and process
while (true) {
// a "blocking" call which waits until a connection is requested
Socket clientSocket = serverSocket.accept();
System.err.println("Accepted connection from client");
// open up IO streams
BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
PrintStream out = new PrintStream(clientSocket.getOutputStream());
// waits for data and reads it in until connection dies
// readLine() blocks until the server receives a new line from client
String s;
while ((s = in.readLine()) != null) {
out.print(s);
}
// close IO streams, then socket
System.err.println("Closing connection with client");
out.close();
in.close();
clientSocket.close();
}
} finally {
serverSocket.close();
}
}
code for the same using NIO
public static void main(String[] args) throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(PORT_NUMBER));
server.socket().setReuseAddress(true);
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
while (true) {
int channelCount = selector.select();
if (channelCount > 0) {
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while (iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
client.configureBlocking(false);
client.register(selector, SelectionKey.OP_READ, client.socket().getPort());
} else if (key.isReadable()) {
SocketChannel client = (SocketChannel) key.channel();
System.out.println("port: " + key.attachment());
if (client.read(buffer) < 0) {
key.cancel();
client.close();
} else {
buffer.flip(); // read from the buffer
/*
* byte[] received = new byte[buffer.remaining()];
* buffer.get(received); buffer.clear(); // write into the buffer
* buffer.put(received); buffer.flip(); // read from the buffer
*/
client.write(buffer);
buffer.clear(); // write into the buffer
}
}
}
}
}
}
Here using normal I/O the main thread comes and wait at the socket.accept() call. But NIO doesn't do that since socketChannel.accept() is not a blocking call.
So wont the NIO program be continuously running the loop ? And result in waste of CPU cycles ? Can I write the program in a better way. Sorry I am very new to JAVA NIO and asynchronous programming.
In normal IO the thread is blocked on serverSocket.accept().
With NIO the thread is blocked on selector.select().
From the JavaDoc of Selector#select():
This method performs a blocking selection operation.
Why is this called "non blocking IO"?
Actually, your first example (with normal IO) has two blocking calls: server.accept() and in.readLine().
Now consider the case with a badly behaving client: it opens a connection to the server, but never sends any data. With normal IO the server thread waits in in.readLine() for data to arrive and cannot serve any other client until the first client closes its connection.
With NIO the picture is different: if a client opens a connection, the server thread wakes up, server.accept()s the connection and registers the SocketChannel with the same selector. Then the server thread waits on the selector once more through selector.select(). Now there are two possibilities to wake up the server thread: either another client connecting, or the first client sending some data.
So the term "non blocking IO" does not mean that the server thread is never blocked - it means that a non-behaving client cannot block the server thread forever.
Related
I just found that the problem might due to multi-threading problem. After the read() method I sent the request to several worker threads to process the data. When the thread pool size is 1, the problem doesn't occur. However, when the thread pool size is bigger than 1, this problem occurs.
I initialized my threadpool before the while(true) loop, and execute my worker thread after the read() method.
I'm using Java NIO in a middleware that connects a memtier client and a memcached server. The system works fine with only one clients connected, however, when there are more clients connected, when one client finishes and closes its channel, the other client won't be able to read or write to its channel any more.
My implementation looks like the following:
public void run() {
try{
// Connect to client
selector = Selector.open();
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
InetSocketAddress address = new InetSocketAddress(8000);
server.socket().bind(address);
server.register(selector,SelectionKey.OP_ACCEPT);
// Connect to Server
Socket socket = new Socket("localhost",8090);
// Select keys
while (true) {
selector.select();
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while(iterator.hasNext()) {
SelectionKey key = iterator.next();
iterator.remove();
// check if key is valid
if(!key.isValid()) {
continue;
}
if(key.isAcceptable()) {
accept(key);
}else if(key.isReadable()) {
read(key);
}
}
}
}
}
My accept() and read() looks like this:
private void accept(SelectionKey key) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel socketChannel = server.accept();
socketChannel.configureBlocking(false);
socketChannel.register(selector, SelectionKey.OP_READ);
}
private void read(SelectionKey key) {
SocketChannel channel = (SocketChannel) key.channel();
buffer.clear();
int n = -1;
n = channel.read(buffer);
if(n == -1) {
key.cancel();
channel.close();
}else{
//read to buffer
}
}
I have tried many ways but still cannot find out the problem. Thank you very much!
This question already has answers here:
How to terminate a thread blocking on socket IO operation instantly?
(2 answers)
Closed 6 years ago.
I have a UDP server listening packets from a client.
socket = new DatagramSocket(port);
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
socket.receive(packet);
}
The receive() method will wait forever before a packet received. Is it possible to stop waiting for receiving? I can set a boolean isListen to stop the loop. On the other hand, if the socket is waiting then it will wait forever if no packet send from the client.
You need to set a socket timeout with the setSoTimeout() method and catch SocketTimeoutException thrown by the socket's receive() method when the timeout's been exceeded. After catching the exception you can keep using the socket for receiving packets. So utilizing the approach in a loop allows you to periodically (according to the timeout set) "interrupt" the receive() method call.
Note that timeout must be enabled prior to entering the blocking operation.
An example (w.r.t your code):
socket = new DatagramSocket(port);
socket.setSoTimeout(TIMEOUT_IN_MILLIS)
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
while (true) {
try {
socket.receive(packet);
break;
} catch (SocketTimeoutException e) {
if (!isListen) {} // implement your business logic here
}
}
// handle the packet received
}
You can close the socket from another thread. The thread blocked in receive() will then throw an IOException.
while (isListen) {
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
try {
socket.receive(packet);
} catch(IOException e) {
continue;
}
}
void stopListening() { // Call me from some other thread
isListen = false;
socket.close();
}
Is there any way to write a multi-client program using sockets in Java without multi-threading?
I heard about socket mapping but how does it work?
I know multi-threading, but for now I should not use it.
Well I just threw this together. This is just an example to programming with java.nio. I think this code is fairly straight forward. It binds a ServerSocket to ports 3000-3009. Whenever a client sends data it will echo it back to them. Itcan handle as many connections as possible. You should implement more error handling of course but it will be harder to read then for reference. Handling data in this way is a bit more difficult than using thread per client approach, if you want it's possible to have a hybrid type server where inactive connections go into non blocking mode and when you start receiving data you can jump back into blocking mode with a cached thread pool.
To test it out just open a shell and use telnet localhost 3000
Selector selector = Selector.open();
for(int port=3000;port<3010;port++){
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(port));
server.register(selector, SelectionKey.OP_ACCEPT);
System.out.println("Bound to " + server);
}
ByteBuffer buffer = ByteBuffer.allocate(0x4000);
while(selector.isOpen()){
selector.select();
Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
while(keys.hasNext()){
SelectionKey key = keys.next();
if(!key.isValid()) continue;
if(key.isReadable()){
buffer.clear();
SocketChannel socket = (SocketChannel)key.channel();
if(socket.read(buffer) == -1){ //-1 is end of stream
System.out.println("Client Disconnected " + socket);
socket.close();
continue;
}else{
buffer.flip();
socket.write(buffer); //echo data back to client
}
}else if(key.isAcceptable()){
ServerSocketChannel serverChannel = (ServerSocketChannel)key.channel();
SocketChannel socket = serverChannel.accept();
socket.configureBlocking(false);
socket.register(selector, SelectionKey.OP_READ);
System.out.println("Client Connected " + socket);
}
}
selector.selectedKeys().clear();
}
I am new to NIO i understand the concept of Asynchronous Socket but i am confused on Non Blocking part.
I am using java NIO Selector . My Code for Server is
public class EcoNonBlockingIOServer_7 {
public static int PORT_NUMBER = 5555;
public static void main(String[] argv) throws Exception {
new EcoNonBlockingIOServer_7().go(argv);
}
public void go(String[] argv) throws Exception {
int port = PORT_NUMBER;
if (argv.length > 0) { // Override default listen port
port = Integer.parseInt(argv[0]);
}
System.out.println("Listening on port " + port);
// Allocate an unbound server socket channel
ServerSocketChannel serverChannel = ServerSocketChannel.open();
// Get the associated ServerSocket to bind it with
ServerSocket serverSocket = serverChannel.socket();
// Create a new Selector for use below
Selector selector = Selector.open();
// Set the port the server channel will listen to
serverSocket.bind(new InetSocketAddress(port));
// Set nonblocking mode for the listening socket
serverChannel.configureBlocking(false);
// Register the ServerSocketChannel with the Selector
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// This may block for a long time. Upon returning, the
// selected set contains keys of the ready channels.
int n = selector.select();
if (n == 0) {
continue; // nothing to do
}
// Get an iterator over the set of selected keys
Iterator it = selector.selectedKeys().iterator();
// Look at each key in the selected set
while (it.hasNext()) {
SelectionKey key = (SelectionKey) it.next();
// Is a new connection coming in?
if (key.isAcceptable()) {
ServerSocketChannel server = (ServerSocketChannel) key.channel();
SocketChannel channel = server.accept();
registerChannel(selector, channel, SelectionKey.OP_READ);
sayHello(channel);
}
// Is there data to read on this channel?
if (key.isReadable()) {
readDataFromSocket(key);
}
// Remove key from selected set; it's been handled
it.remove();
}
}
}
Now My Queries are:
If we register a channel with selector on any operation it always get blocked on selector.select() then how it is non blocking.
If we admit it uses OP_ACCEPT as key and maps channel accordingly but again In key is acceptable i am modifying this channel selector to OP_READ since it already has been accepted. Again It blocks on selector.select() for read event
*Please correct my understanding if i am wrong *
If we register a channel with selector on any operation it always get blocked on selector.select() then how it is non blocking.
select() is blocking. Every operation on a non-blocking channel itself is non-blocking, i.e. read() and write().
If we admit it uses OP_ACCEPT as key and maps channel accordingly but again In key is acceptable i am modifying this channel selector to OP_READ since it already has been accepted.
Very confused. The channel whose interest-ops == OP_ACCEPT is the listening socket. The channel you accepted from the listening socket is a connected socket, and it is this socket that you put into non-blocking mode, register with OP_ACCEPT, etc.
Again It blocks on selector.select() for read event
Correct, but it doesn't block in read() or write() or accept() or finishConnect(). Using a selector is actually called multiplexed I/O: you wait for multiple channels and multiple events at the same time in a single operation.
I am writing a server program that can accept communication from multiple (but fixed) number of clients. I want to keep the program single-threaded. To do so, I am using non-blocking socket to iterate over each client, but each client's channel uses blocking mode. Here's my server code:
class server {
public static void main(String args[])
throws Exception {
ServerSocketChannel channel = ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().bind(new java.net.InetSocketAddress("localhost", 8005));
System.out.println("Server attivo porta 8005");
Selector selector = Selector.open();
channel.register(selector, SelectionKey.OP_ACCEPT);
for(;;) {
selector.select();
Set keys = selector.selectedKeys();
Iterator i = keys.iterator();
while(i.hasNext()) {
SelectionKey key = (SelectionKey) i.next();
i.remove();
if (key.isAcceptable()) {
SocketChannel client = channel.accept();
client.configureBlocking(true);
ObjectInputStream ois = new ObjectInputStream(
client.socket().getInputStream());
String s = (String)ois.readObject();
System.out.println(s);
}
}
}
}
}
The client uses simple blocking I/O, as shown here:
class client {
public static void main(String args[]) throws Exception {
SocketChannel channel = SocketChannel.open();
channel.configureBlocking(true);
channel.connect(new java.net.InetSocketAddress("localhost", 8005));
ObjectOutputStream oos = new ObjectOutputStream
(channel.socket().getOutputStream());
for (int i = 0; i < 100; i++) {
oos.writeObject(new String("Hello " + i));
System.out.println(i);
}
}
}
The problem is that although the client wants to write 100 times, the server is reading the message just once. Neither the server nor the client is giving any exception, but I am only getting the output "Hello 0" from the server. Is there any problem in what I am doing here? If so, what alternatives do I have?
Thanks.
Update: Closing the ObjectInputStream within the server's loop gives a BrokenPipeException by the client (the server behaves in the same way).
The issue is that you're just checking for new connections with key.isAcceptable(). You also need to check for reads with key.isReadble(). You should only be doing connection setup from key.isAcceptable().
See Java ServerSocketChannel SocketChannel (Callback)
The problem is that the server is not waiting for the client to send all it's data. In client server programs, what you need to do is to establish a clear protocol between both so that they are in sync when data is transmitted/received. This is usually done by signaling an end of transmission by either side by sending a designated symbol or closing the connection when they are done