I am reading following tutorial:
http://tutorials.jenkov.com/java-nio/selectors.html
I am feeling that I am didn't understand a lot of details of following article but I am trying to invoke example at the end of the article.
my final code looks so:
public static void main(String[] args) throws IOException {
ServerSocketChannel channel = ServerSocketChannel.open();
Selector selector = Selector.open();
channel.configureBlocking(false);
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
while (true) {
int readyChannels = selector.select();
if (readyChannels == 0) continue;
Set<SelectionKey> selectedKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectedKeys.iterator();//cause of exception
while (keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
if (key.isAcceptable()) {
// a connection was accepted by a ServerSocketChannel.
} else if (key.isConnectable()) {
// a connection was established with a remote server.
} else if (key.isReadable()) {
// a channel is ready for reading
} else if (key.isWritable()) {
// a channel is ready for writing
}
keyIterator.remove();
}
}
}
As a result of this method invokation I see follwing stacktrace:
Exception in thread "main" java.lang.IllegalArgumentException
at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:196)
at java.nio.channels.SelectableChannel.register(SelectableChannel.java:277)
...
update
my full code variant:
public class NioSelectorTest {
public static void main(String[] args) {
new Thread(new Receiver()).start();
new Thread(new Sender()).start();
}
}
class Receiver implements Runnable {
private static byte[] data = new byte[255];
public void run() {
try {
for (int i = 0; i < data.length; i++)
data[i] = (byte) i;
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(9000));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set readyKeys = selector.selectedKeys();
Iterator iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
System.out.println("Accepted connection from " + client);
client.configureBlocking(false);
ByteBuffer source = ByteBuffer.wrap(data);
SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE);
key2.attach(source);
} else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer output = (ByteBuffer) key.attachment();
if (!output.hasRemaining()) {
output.rewind();
}
client.write(output);
}
key.channel().close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Sender implements Runnable {
public void run() {
try {
SocketChannel sChannel = SocketChannel.open();
sChannel.configureBlocking(false);
sChannel.connect(new InetSocketAddress("localhost", 9000));
while (!sChannel.finishConnect()) {
ByteBuffer buf = ByteBuffer.allocateDirect(1024);
buf.put((byte) 0xFF);
buf.flip();
int numBytesWritten = sChannel.write(buf);
System.out.println("sent " + numBytesWritten + " bytes");
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
In console I see
Accepted connection from java.nio.channels.SocketChannel[connected
local=/127.0.0.1:9000 remote=/127.0.0.1:50940]
In debug I see that I cannot to enter into this loop:
while (!sChannel.finishConnect()) {
...
SelectionKey selectionKey = channel.register(selector, SelectionKey.OP_READ);
This should be OP_ACCEPT for a ServerSocketChannel.
In Java documentation it's written that register method throws
IllegalArgumentException - If a bit in ops does not correspond to an operation that is supported by this channel, that is, if set & ~validOps() != 0
(Source: http://bit.ly/1lSBdX8)
I think you need to bind a specific port at first, and register selector on that SocketChannel. So the beginning of your code should look like this:
ServerSocketChannel channel = ServerSocketChannel.open();
channel.socket().bind(new InetSocketAddress(8080)); // 8080 is the port you'll be listening
SocketChannel socketChannel = serverSocketChannel.accept();
Selector selector = Selector.open();
socketChannel.configureBlocking(false);
SelectionKey selectionKey = socketChannel.register(selector, SelectionKey.OP_READ);
...
Related
I'm trying java nio's socket server channel and selector as below:
try { // server side main function
ServerSocketChannel listenChannel = ServerSocketChannel.open();
listenChannel.socket().bind(new InetSocketAddress(12112));
Selector selector = Selector.open();
listenChannel.configureBlocking(false);
listenChannel.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
if (selector.select(TIMEOUT) == 0) {
System.out.print(".");
continue;
}
Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();
if (key.isAcceptable()) {
SocketChannel channel = listenChannel.accept();
channel.configureBlocking(false);
SelectionKey connKey = channel.register(selector, SelectionKey.OP_ACCEPT);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
Then a simple client like:
try {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 12112));
ByteBuffer writeBuffer = ByteBuffer.allocate(32);
ByteBuffer readBuffer = ByteBuffer.allocate(32);
writeBuffer.put("hello".getBytes());
writeBuffer.flip();
while (true) {
writeBuffer.rewind();
socketChannel.write(writeBuffer);
readBuffer.clear();
socketChannel.read(readBuffer);
}
} catch (IOException e) {
}
First I start the server and then client, the server will be connect and throw exception like below:
..................java.lang.IllegalArgumentException
at java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:199)
at java.nio.channels.SelectableChannel.register(SelectableChannel.java:280)
at NIOServer.main(myServer.java:32)
So what happened when client connects? Why register function throws out exception and how to fix it?
The SocketChannel has the valid option only for OP_READ,OP_WRITE,OP_CONNECT.
Please check SocketChannel.validOps()
If it fails in channel.register(selector, SelectionKey.OP_ACCEPT) then you have to change it to
channel.register(selector, SelectionKey.OP_READ);
Only ServerSocketChannel supports SelectionKey.OP_ACCEPT.
listenChannel.accept() create new channel which supports read and write operations.
I have some server and client code that use nio in java. When I try connected to the server sctpChannel.connect(new InetSocketAddress("127.0.0.1",4545)); returns false. And selector.select() returns 0 . I can't figure out why it happens.
public class SctpNioServer {
public static void main(String[] args)throws Exception{
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost",4545);
SctpServerChannel serverChannel = SctpServerChannel.open();
serverChannel.bind(inetSocketAddress);
serverChannel.configureBlocking(false);
Selector selector = Selector.open();
serverChannel.register(selector,SelectionKey.OP_ACCEPT );
while(true){
try{
selector.select();
Set<SelectionKey> selectedKeys = selector.selectedKeys() ;
Iterator<SelectionKey> iterator = selectedKeys.iterator();
while (iterator.hasNext()){
SelectionKey key = iterator.next();
iterator.remove();
if(key.isAcceptable()){
SctpChannel channel = serverChannel.accept();
channel.configureBlocking(false) ;
channel.register(selector,SelectionKey.OP_READ);
}
if (key.isReadable()){
SctpChannel channel = (SctpChannel) key.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
channel.receive(byteBuffer,null,null);
byteBuffer.flip();
while (byteBuffer.hasRemaining()){
System.out.println((char)byteBuffer.get());
}
byteBuffer.clear();
channel.register(selector, SelectionKey.OP_WRITE);
}
if(key.isWritable()){
//doSomething
}
}
selector.wakeup();
}
catch (IOException e){
e.printStackTrace();
}
finally {
serverChannel.close();
}
}
}}
public class SctpNioClient {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
try {
SctpChannel channel = SctpChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress("localhost", 4545));
Selector sel = Selector.open();
channel.register(sel, SelectionKey.OP_CONNECT);
while (true) {
if (sel.isOpen()) {
int keys = sel.select(5);
if (keys > 0) {
Set<SelectionKey> selectedKeys = sel.selectedKeys();
for (SelectionKey sk : selectedKeys) {
if (!sk.isValid()) {
break;
}
if (sk.isConnectable()) {
channel.finishConnect();
channel.register(sel, SelectionKey.OP_WRITE, channel);
}
if (sk.isWritable()) {
SctpChannel ch = (SctpChannel) sk.channel();
System.out.println("writing->");
ByteBuffer byteBuffer = ByteBuffer.allocate(4096);
String text = scanner.nextLine();
byteBuffer.clear();
byteBuffer.put(text.getBytes());
byteBuffer.flip();
MessageInfo messageInfo = MessageInfo.createOutgoing(null,null,0);
ch.send(byteBuffer,messageInfo);
ch.register(sel , SelectionKey.OP_READ);
sel.wakeup();
}
if(sk.isReadable()){
SctpChannel ch = (SctpChannel) sk.channel();
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
ch.receive(byteBuffer,null,null);
byteBuffer.flip();
while (byteBuffer.hasRemaining()){
System.out.println((char)byteBuffer.get());
}
ch.register(sel,SelectionKey.OP_WRITE);
} } } } }
} catch (IOException ex) { }
}}
connect() returns a boolean. You claim that it is false, but your code ignores it.
If it returns true, you don't need to register for OP_CONNECT: but as you are ignoring it you are also ignoring this fact.
finishConnect() also returns a boolean, which you are also ignoring.
All these operations can throw IOExceptions, which you are also ignoring.
Solution: don't. In all cases.
friends! I'm new to Java NIO and I'm currently trying to make a non-blocking chat app. The client connects to the server without problem. The client writes a message or few messages to the server but the server starts reading the messages only when the Socket connection is closed from the client code, so a SocketChannel (or only Socket) must be created and closed in the client code for every message - this doesn't seems to me right. I've tried the client side with simple Java I/O and also with NIO Selector. Same problem - the server starts to read only when the SocketChannel or the Socket is closed from client. Can somebody please tell me the proper way of doing such non blocking connections or show me the error in my logic... Thank You very much!
This is the server code:
public class NIOServer implements Runnable {
#Override
public void run() {
try {
runServer();
} catch (IOException e) {
e.printStackTrace();
}
}
private void runServer() throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(8080));
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
int readyChannels = selector.selectNow();
if(readyChannels==0){
continue;
}
System.out.println("Ready channels: "+readyChannels);
Set<SelectionKey> selectionKeys = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
while(keyIterator.hasNext()) {
SelectionKey key = keyIterator.next();
keyIterator.remove();
if(key.isAcceptable()){
ServerSocketChannel acceptableServer = (ServerSocketChannel)key.channel();
SocketChannel client = server.accept();
if(client!=null){
System.out.println("Client accepted!");
client.configureBlocking(false);
SelectionKey selectionKey = client.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}
}
if (key.isReadable()) {
read(key);
}
/*if(key.isConnectable()){
System.out.println("connectable");
}
if(key.isWritable()){
//System.out.println("writable");
}*/
}
}
}
public void read(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
channel.configureBlocking(false);
ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.clear();
int bytesRead = channel.read(buffer);
while(bytesRead>0){
System.out.println("Read bytes: "+ bytesRead);
bytesRead=channel.read(buffer);
if(bytesRead==-1){
channel.close();
key.cancel();
}
buffer.flip();
while(buffer.hasRemaining()){
System.out.print((char)buffer.get());
}
}
//key.cancel();
//channel.close();
}
}
Client with NIO Selector:
public class NIOSelectorClient implements Runnable{
private Selector selector;
#Override
public void run() {
try {
startClient();
} catch (IOException e) {
e.printStackTrace();
}
}
public void startClient() throws IOException {
SocketChannel socketChannel= openConnection();
selector = Selector.open();
socketChannel.register(selector,SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
while(!Thread.interrupted()) {
int readyChannels = selector.selectNow();
if(readyChannels==0) {
continue;
}
Set<SelectionKey> keySet = selector.selectedKeys();
Iterator<SelectionKey> keyIterator = keySet.iterator();
while(keyIterator.hasNext()) {
SelectionKey currentKey = keyIterator.next();
keyIterator.remove();
if(!currentKey.isValid()) {
continue;
}
if(currentKey.isConnectable()) {
System.out.println("I'm connected to the server!");
handleConnectable(currentKey);
}
if(currentKey.isWritable()){
handleWritable(currentKey);
}
}
}
}
private void handleWritable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100);
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message to server: ");
String output = scanner.nextLine();
buffer.put(output.getBytes());
buffer.flip();
//while(buffer.hasRemaining()) {
channel.write(buffer);
//}
System.out.println("Message send");
buffer.clear();
channel.close();
key.cancel();
}
private void handleConnectable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if(channel.isConnectionPending()) {
channel.finishConnect();
}
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
}
private static SocketChannel openConnection() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
socketChannel.configureBlocking(false);
while(!socketChannel.finishConnect()) {
System.out.println("waiting connection....");
}
return socketChannel;
}
}
And this is the non-NIO cliet:
public class NIOClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8080);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(socket.isConnected()) {
//synchronized (socket) {
writeMessage(socket,writer);
//readServerMessage(socket);
//}
}
}
public static void writeMessage(Socket socket, BufferedWriter writer) throws IOException {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message: ");
String output = "Client 1: " + scanner.nextLine();
writer.write(output);
writer.flush();
//writer.close();
}
public static void readServerMessage(Socket socket) throws IOException {
}
}
Your code suffers from the usual raft of NIO mistakes:
public class NIOServer implements Runnable {
private void runServer() throws IOException {
ServerSocketChannel server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(8080));
server.configureBlocking(false);
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while(true) {
int readyChannels = selector.selectNow();
You are selecting without a sleep. If there are no ready channels this loop will smoke the CPU. Use a timeout, even a short one.
SelectionKey selectionKey = client.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
You should not register for OP_WRITE unless you've already written something and got a short return value.
public void read(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
channel.configureBlocking(false);
The channel is already in non-blocking mode. You put it there when you accepted it. You couldn't have selected on it unless it was in non-blocking mode. Remove.
ByteBuffer buffer = ByteBuffer.allocate(100);
buffer.clear();
The buffer is already clear. You just created it. Remove.
int bytesRead = channel.read(buffer);
while(bytesRead>0){
System.out.println("Read bytes: "+ bytesRead);
bytesRead=channel.read(buffer);
if(bytesRead==-1){
channel.close();
key.cancel();
Closing the channel cancels the key. You don't need both. Remove the cancel.
//key.cancel();
//channel.close();
Remove. Don't leave dead code lying around to confuse future readers.
Client with NIO Selector:
public class NIOSelectorClient implements Runnable{
private Selector selector;
public void startClient() throws IOException {
SocketChannel socketChannel= openConnection();
selector = Selector.open();
socketChannel.register(selector,SelectionKey.OP_CONNECT|SelectionKey.OP_READ|SelectionKey.OP_WRITE);
See above.
while(!Thread.interrupted()) {
int readyChannels = selector.selectNow();
See above.
if(!currentKey.isValid()) {
continue;
}
Very good but you need this test before every other one below, e.g. currentKey.isValid() && currentKey.isReadable(), because a prior handler may have closed the channel or cancelled the key. Same applies in the server code.
if(currentKey.isConnectable()) {
System.out.println("I'm connected to the server!");
handleConnectable(currentKey);
}
if(currentKey.isWritable()){
handleWritable(currentKey);
}
You never handle isReadable() in the client. Don't you expect any input?
private void handleWritable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel)key.channel();
ByteBuffer buffer = ByteBuffer.allocate(100);
Scanner scanner = new Scanner(System.in);
System.out.println("Enter message to server: ");
String output = scanner.nextLine();
Here you are blocking the entire client including all its SocketChannels waiting for the user to enter some input. This is very poor design.
buffer.clear();
You don't need this. You're about to release the buffer as a local variable. You're done with it.
channel.close();
You're closing the channel after one write? Why?
key.cancel();
Closing the channel cancels the key. You don't need both. You don't need this. Remove.
private void handleConnectable(SelectionKey key) throws IOException {
SocketChannel channel = (SocketChannel) key.channel();
if(channel.isConnectionPending()) {
channel.finishConnect();
finishConnect() can return false, in which case you should do nothing further in this method.
channel.configureBlocking(false);
The channel is already in blocking mode. Otherwise you couldn't have got here. Remove.
channel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
}
See above re OP_WRITE.
private static SocketChannel openConnection() throws IOException {
SocketChannel socketChannel = SocketChannel.open();
socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));
socketChannel.configureBlocking(false);
while(!socketChannel.finishConnect()) {
System.out.println("waiting connection....");
}
Remove this loop. That's what OP_CONNECT is for. You are keeping a dog and barking yourself. If you want not to proceed out of here until the connection is complete, do it in blocking mode. Instead of just smoking the CPU.
And this is the non-NIO cliet:
public class NIOClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 8080);
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
while(socket.isConnected()) {
The socket is connected. You connected it when you constructed it. It stays that way. isConnected() is not a valid test for peer disconnection.
I try to implement a UDP client server detection via broadcast. The idea is the following: I have a server, which is bound to port 12344 and a client which is bound to port 12345. Now, the client sends a broadcast package to 255.255.255.255 12344. The server should reply to this package with a other package to IPClient:12345.
The implementation uses Java nio.
The problem is, that on windows, the server gets the packages but cannot(?) send an answer (I don't see the answer in wireshark).
I have the following example code:
Client
public final class ASyncUDPClient {
public static void main(String[] args) throws IOException {
InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
System.out.println(hostAddress);
// Create a non-blocking socket channel
DatagramChannel channel = DatagramChannel.open();
channel.socket().setBroadcast(true);
channel.socket().bind(new InetSocketAddress(getAddress(), 12345));
channel.configureBlocking(false);
// Kick off connection establishment
channel.connect(hostAddress);
ByteBuffer buffer = getBuffer();
Selector selector = Selector.open();
channel.write(buffer);
System.out.println("data send");
channel.register(selector, SelectionKey.OP_READ);
while (true) {
final int select = selector.select();
System.out.println("select " + select);
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
System.out.println("key selected");
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
System.out.println("read");
} else if (key.isWritable()) {
System.out.println("write");
}
}
}
}
private static ByteBuffer getBuffer() throws CharacterCodingException {
return Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("1234"));
}
private static InetAddress getAddress() throws SocketException {
final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface networkInterfaceToUse = null;
while (networkInterfaces.hasMoreElements()) {
final NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.getDisplayName().contains("Virtual")) continue;
if (networkInterface.isVirtual()) continue;
if (networkInterface.isLoopback()) continue;
if (!networkInterface.isUp()) continue;
networkInterfaceToUse = networkInterface;
System.out.println(networkInterfaceToUse);
}
return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}
}
Server example
public class ASyncUDPSvr {
static int BUF_SZ = 1024;
static int port = 12344;
static public void main(String[] args) {
ASyncUDPSvr svr = new ASyncUDPSvr();
svr.process();
}
private static InetAddress getAddress() throws SocketException {
final Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
NetworkInterface networkInterfaceToUse = null;
while (networkInterfaces.hasMoreElements()) {
final NetworkInterface networkInterface = networkInterfaces.nextElement();
if (networkInterface.getDisplayName().contains("Virtual")) continue;
if (networkInterface.isVirtual()) continue;
if (networkInterface.isLoopback()) continue;
if (!networkInterface.isUp()) continue;
networkInterfaceToUse = networkInterface;
System.out.println(networkInterfaceToUse);
}
return networkInterfaceToUse.getInterfaceAddresses().get(1).getAddress();
}
private void process() {
try {
Selector selector = Selector.open();
DatagramChannel channel = DatagramChannel.open();
InetSocketAddress isa = new InetSocketAddress(getAddress(), port);
channel.socket().bind(isa);
channel.configureBlocking(false);
SelectionKey clientKey = channel.register(selector, SelectionKey.OP_READ);
clientKey.attach(new Con());
while (true) {
try {
selector.select();
Iterator selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
try {
SelectionKey key = (SelectionKey) selectedKeys.next();
selectedKeys.remove();
if (!key.isValid()) {
continue;
}
if (key.isReadable()) {
read(key);
key.interestOps(SelectionKey.OP_WRITE);
} else if (key.isWritable()) {
write(key);
key.interestOps(SelectionKey.OP_READ);
}
} catch (IOException e) {
System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
} catch (IOException e) {
System.err.println("glitch, continuing... " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
} catch (IOException e) {
System.err.println("network error: " + (e.getMessage() != null ? e.getMessage() : ""));
}
}
private void read(SelectionKey key) throws IOException {
DatagramChannel chan = (DatagramChannel) key.channel();
Con con = (Con) key.attachment();
con.sa = chan.receive(con.req);
System.out.println("sender address: " + con.sa + "rcv: " + new String(con.req.array(), "UTF-8"));
con.resp = Charset.forName("UTF-8").newEncoder().encode(CharBuffer.wrap("send string"));
}
private void write(SelectionKey key) throws IOException {
DatagramChannel chan = (DatagramChannel) key.channel();
Con con = (Con) key.attachment();
System.out.println("sending data: " + new String(con.resp.array(), "UTF-8") + " to " + con.sa);
chan.send(con.resp, con.sa);
System.out.println("data send");
}
class Con {
ByteBuffer req;
ByteBuffer resp;
SocketAddress sa;
public Con() {
req = ByteBuffer.allocate(BUF_SZ);
}
}
}
InetSocketAddress hostAddress = new InetSocketAddress("255.255.255.255", 12344);
// ...
channel.connect(hostAddress);
The problem is here. You can't connect to the broadcast address, and in any case it doesn't make sense. The broadcast address isn't sending to you, you are sending to it. The server is sending to you from its own bind-address. Just remove this line. You will have to use DatagramChannel.send() rather than write(), as you are unconnected.
The accepted answer is not true. You can "connect" the channel to the broadcast address when you first set:
channel.socket().setBroadcast(true);
Of course UDP is a connectionless protocol, but a "connected" DatagramChannel has some benefits, one of them is the ability to use the write(ByteBuffer[]) method.
I have created a simple server client application using java NIO.
I used a single selector there for accepting connection, reading data and writing.
But I want an application where 1 selector will be busy in accepting the connection while the 2nd selector will read the data and the 3rd selector will write the data.
Means I donot want to put all the load into single selector.
How to achieve this?
Is there any online help
Thanks
Deepak.
// Create the selector
Selector selector = Selector.open();
// Create two non-blocking server sockets on 80 and 81
ServerSocketChannel ssChannel1 = ServerSocketChannel.open();
ssChannel1.configureBlocking(false);
ssChannel1.socket().bind(new InetSocketAddress(80));
// Register both channels with selector
ssChannel1.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
// Wait for an event
selector.select();
// Get list of selection keys with pending events
Iterator it = selector.selectedKeys().iterator();
// Process each key
while (it.hasNext()) {
// Get the selection key
SelectionKey selKey = (SelectionKey)it.next();
// Remove it from the list to indicate that it is being processed
it.remove();
// Check if it's a connection request
if (selKey.isAcceptable()) {
// Get channel with connection request
ServerSocketChannel ssChannel = (ServerSocketChannel)selKey.channel();
// Accepting a Connection on a ServerSocketChannel
SocketChannel sChannel = serverSocketChannel.accept();
// If serverSocketChannel is non-blocking, sChannel may be null
if (sChannel == null) {
// There were no pending connection requests; try again later.
// To be notified of connection requests,
} else {
// Use the socket channel to communicate with the client
}
}
}
}
Usually, on a non-blocking tcp server, first accept, then read, then write,
you need to register the selector in this order to make sense.
Example code
Here is a full example of non-blocking io:
TcpChannelTest.java: (a TestNG testing class)
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets;
import java.util.Iterator;
import java.util.Set;
import org.testng.annotations.Test;
/**
* tcp channel test
*
* #author eric
* #date Sep 2, 2012 9:17:40 PM
*/
public class TcpChannelTest {
public String serverHost = "localhost";
public int serverPort = 12345;
private ServerSocketChannel server;
private int clientSerial = 0;
private int clientCount = 5;
// test tcp non-blocking channel,
#Test
public void testTcpNonBlockingChanne() throws IOException, InterruptedException {
// start server
startServerNonBlocking();
Thread.sleep(500); // wait server to be ready, before start client,
// start clients
for (int i = 0; i < clientCount; i++) {
startClientOnce();
}
// shutdown server,
Thread.sleep(500); // wait client to be handled,
shutdownServer();
}
// start non-blocking server,
private void startServerNonBlocking() throws IOException {
new Thread(new Runnable() {
#Override
public void run() {
try {
server = ServerSocketChannel.open();
server.socket().bind(new InetSocketAddress(serverHost, serverPort)); // bind,
server.configureBlocking(false); // non-blocking mode,
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
while (true) {
selector.select();
Set<SelectionKey> readyKeys = selector.selectedKeys();
// process each ready key...
Iterator<SelectionKey> iterator = readyKeys.iterator();
while (iterator.hasNext()) {
SelectionKey key = (SelectionKey) iterator.next();
iterator.remove();
if (key.isAcceptable()) {
SocketChannel client = server.accept();
System.out.printf("[%s]:\t%s\n", Thread.currentThread().getName(), "accept connection");
client.configureBlocking(false);
// prepare for read,
client.register(selector, SelectionKey.OP_READ);
} else if (key.isReadable()) {
// read
SocketChannel client = (SocketChannel) key.channel();
ByteBuffer inBuf = ByteBuffer.allocate(1024);
while (client.read(inBuf) > 0) {
System.out.printf("[%s]:\t%s\n", Thread.currentThread().getName(), new String(inBuf.array(), StandardCharsets.UTF_8));
}
// prepare for write,
client.register(selector, SelectionKey.OP_WRITE);
} else if (key.isWritable()) {
SocketChannel client = (SocketChannel) key.channel();
String response = "hi - from non-blocking server";
byte[] bs = response.getBytes(StandardCharsets.UTF_8);
ByteBuffer buffer = ByteBuffer.wrap(bs);
client.write(buffer);
// switch to read, and disable write,
client.register(selector, SelectionKey.OP_READ);
}
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}, "t-server-threads").start();
}
// close server,
private void shutdownServer() {
try {
if (server != null) {
server.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* <p>
* tcp client - via channel,
* </p>
* <p>
* It send once request.
* </p>
*
* #throws IOException
*/
private void startClientOnce() throws IOException {
// start client in a new thread
new Thread(new Runnable() {
#Override
public void run() {
try {
SocketChannel client = SocketChannel.open(new InetSocketAddress(serverHost, serverPort));
// write
String request = "hello - from client [" + Thread.currentThread().getName() + "}";
byte[] bs = request.getBytes(StandardCharsets.UTF_8);
ByteBuffer buffer = ByteBuffer.wrap(bs);
while (buffer.hasRemaining()) {
client.write(buffer);
}
// read
ByteBuffer inBuf = ByteBuffer.allocate(1024);
while (client.read(inBuf) > 0) {
System.out.printf("[%s]:\t%s\n", Thread.currentThread().getName(), new String(inBuf.array(), StandardCharsets.UTF_8));
}
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}, "t-channelClient-" + clientSerial++).start();
}
}
It is possible to register a channel with multiple Selectors using register(Selector sel, int ops). You then register different interest ops on each of the selectors:
// After the accepting a connection:
SelectionKey readKey = sChannel.register(readSelector, SelectionKey.OP_READ);
// When you have something to write:
SelectionKey writeKey = sChannel.register(writeSelector, SelectionKey.OP_WRITE);