Simple Echo Server - Binds to both TCP and UDP ports 5050, and 5051 and will echo all data received to all other connections. It will treat all data as a String so use "telnet localhost 5050" or if you have netcat you can use "nc -u localhost 5050" to send udp packets to the server.
Solution:
/*
Simple Echo Server
Binds to both TCP and UDP ports 5050, and 5051
and will echo all data received to all other
connections. It will treat all data as a String
so use "telnet localhost 5050" or if you have
netcat you can use "nc -u localhost 5050" to
send udp packets to the server.
*/
package nioexample;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
public class NioExample implements Runnable{
final private Thread nioThread;
final private Selector selector;
final private Queue<Runnable> runnableQueue = new LinkedList<Runnable>();
final private List<Attachment> attachments = new ArrayList<Attachment>();
public NioExample() throws IOException{
selector = Selector.open();
nioThread = new Thread(this);
nioThread.setName("NioExample");
}
public void start(){
if(!nioThread.isAlive()) nioThread.start();
}
@Override
public void run() {
ByteBuffer reusableBuffer = ByteBuffer.allocate(0x4000);
while(selector.isOpen()){
if(!runnableQueue.isEmpty()) handleQueue();
try{
handleSelect(reusableBuffer);
}catch(Exception e){
e.printStackTrace();
}
}
}
public void runOnNioThread(Runnable runnable){
synchronized(runnableQueue){
runnableQueue.add(runnable);
selector.wakeup();
}
}
private void handleQueue(){
synchronized(runnableQueue){
Runnable runnable;
while((runnable = runnableQueue.poll()) != null) runnable.run();
}
}
private void handleSelect(ByteBuffer buffer) throws IOException{
int totalKeys = selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while(selectedKeys.hasNext()){
buffer.clear();
SelectionKey key = selectedKeys.next();
SelectableChannel channel = key.channel();
Attachment attachment = (Attachment)key.attachment();
try{
if(key.isValid()){
if(key.isReadable()){
if(channel instanceof DatagramChannel){
DatagramChannel dChannel = (DatagramChannel)channel;
SocketAddress remote = dChannel.receive(buffer);
if(remote != null){
buffer.flip();
attachment.onReceiveData(buffer, remote);
}else{
}
}else if(channel instanceof SocketChannel){
SocketChannel sChannel = (SocketChannel)channel;
int bytesRead = sChannel.read(buffer);
buffer.flip();
if(bytesRead == -1){
key.cancel();
attachment.onClosed();
}else{
attachment.onReceiveData(buffer);
}
}
}else if(key.isAcceptable()){
ServerSocketChannel ssChannel = (ServerSocketChannel)channel;
SocketChannel sChannel = ssChannel.accept();
sChannel.configureBlocking(false);
Attachment sAttachment = new Attachment();
sAttachment.channel = sChannel;
sChannel.register(selector, SelectionKey.OP_READ, sAttachment);
sAttachment.onStart();
}
}else{ //INVALID KEY
}
}catch(Exception e){
key.cancel();
attachment.onClosed();
e.printStackTrace();
}finally{
selectedKeys.remove();
}
}
}
public Attachment createServerSocket(final SocketAddress address){
final Attachment attachment = new Attachment();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
ServerSocketChannel ssChannel = ServerSocketChannel.open();
attachment.channel = ssChannel;
ssChannel.configureBlocking(false);
ssChannel.socket().bind(address);
ssChannel.register(selector, SelectionKey.OP_ACCEPT, attachment);
attachment.onStart();
} catch (IOException e) {
attachment.onClosed();
e.printStackTrace();
}
}
};
runOnNioThread(runnable);
return attachment;
}
public Attachment createDatagramSocket(final SocketAddress address){
final Attachment attachment = new Attachment();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
DatagramChannel dChannel = DatagramChannel.open();
attachment.channel = dChannel;
dChannel.configureBlocking(false);
dChannel.socket().bind(address);
dChannel.register(selector, SelectionKey.OP_READ, attachment);
attachment.onStart();
} catch (IOException e) {
attachment.onClosed();
e.printStackTrace();
}
}
};
runOnNioThread(runnable);
return attachment;
}
public void sendToAll(ByteBuffer buffer){
for(Attachment a:attachments){
try {
if(a.channel instanceof SocketChannel){
a.send(buffer);
buffer.flip();
}else if(a.channel instanceof DatagramChannel){
a.sendToAll(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
NioExample nio = new NioExample();
nio.start();
nio.createServerSocket(new InetSocketAddress(5050));
nio.createServerSocket(new InetSocketAddress(5051));
nio.createDatagramSocket(new InetSocketAddress(5050));
nio.createDatagramSocket(new InetSocketAddress(5051));
}
public class Attachment{
SelectableChannel channel;
Map<SocketAddress, Long> remoteAddresses = new HashMap<SocketAddress, Long>();
void onStart(){
attachments.add(this);
System.out.println("Started Listening " + channel);
}
void onReceiveData(ByteBuffer buffer){
System.out.printf("Received TCP(%s): %s\n",
((SocketChannel)channel).socket().getRemoteSocketAddress(),
new String(buffer.array(), buffer.position(), buffer.limit()));
NioExample.this.sendToAll(buffer);
}
void onReceiveData(ByteBuffer buffer, SocketAddress remote){
remoteAddresses.put(remote, System.currentTimeMillis());
System.out.printf("Received UDP(%s): %s\n",
remote, new String(buffer.array(), buffer.position(), buffer.limit()));
NioExample.this.sendToAll(buffer);
}
void onClosed(){
attachments.remove(this);
System.out.println("Closed " + channel);
}
public synchronized void send(ByteBuffer data) throws IOException{
SocketChannel sChannel = (SocketChannel)channel;
sChannel.write(data);
}
public synchronized void sendTo(ByteBuffer data, SocketAddress remote) throws IOException{
if((System.currentTimeMillis() - remoteAddresses.get(remote)) > (TimeUnit.MINUTES.toMillis(5))){
remoteAddresses.remove(remote);
System.out.println("Deleted Entry " + remote);
return;
}
DatagramChannel dChannel = (DatagramChannel)channel;
dChannel.send(data, remote);
}
public void sendToAll(ByteBuffer data) throws IOException{
Iterator<SocketAddress> addresses = remoteAddresses.keySet().iterator();
while(addresses.hasNext()){
sendTo(data, addresses.next());
data.flip();
}
}
}
}
Solution:
/*
Simple Echo Server
Binds to both TCP and UDP ports 5050, and 5051
and will echo all data received to all other
connections. It will treat all data as a String
so use "telnet localhost 5050" or if you have
netcat you can use "nc -u localhost 5050" to
send udp packets to the server.
*/
package nioexample;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
public class NioExample implements Runnable{
final private Thread nioThread;
final private Selector selector;
final private Queue<Runnable> runnableQueue = new LinkedList<Runnable>();
final private List<Attachment> attachments = new ArrayList<Attachment>();
public NioExample() throws IOException{
selector = Selector.open();
nioThread = new Thread(this);
nioThread.setName("NioExample");
}
public void start(){
if(!nioThread.isAlive()) nioThread.start();
}
@Override
public void run() {
ByteBuffer reusableBuffer = ByteBuffer.allocate(0x4000);
while(selector.isOpen()){
if(!runnableQueue.isEmpty()) handleQueue();
try{
handleSelect(reusableBuffer);
}catch(Exception e){
e.printStackTrace();
}
}
}
public void runOnNioThread(Runnable runnable){
synchronized(runnableQueue){
runnableQueue.add(runnable);
selector.wakeup();
}
}
private void handleQueue(){
synchronized(runnableQueue){
Runnable runnable;
while((runnable = runnableQueue.poll()) != null) runnable.run();
}
}
private void handleSelect(ByteBuffer buffer) throws IOException{
int totalKeys = selector.select();
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while(selectedKeys.hasNext()){
buffer.clear();
SelectionKey key = selectedKeys.next();
SelectableChannel channel = key.channel();
Attachment attachment = (Attachment)key.attachment();
try{
if(key.isValid()){
if(key.isReadable()){
if(channel instanceof DatagramChannel){
DatagramChannel dChannel = (DatagramChannel)channel;
SocketAddress remote = dChannel.receive(buffer);
if(remote != null){
buffer.flip();
attachment.onReceiveData(buffer, remote);
}else{
}
}else if(channel instanceof SocketChannel){
SocketChannel sChannel = (SocketChannel)channel;
int bytesRead = sChannel.read(buffer);
buffer.flip();
if(bytesRead == -1){
key.cancel();
attachment.onClosed();
}else{
attachment.onReceiveData(buffer);
}
}
}else if(key.isAcceptable()){
ServerSocketChannel ssChannel = (ServerSocketChannel)channel;
SocketChannel sChannel = ssChannel.accept();
sChannel.configureBlocking(false);
Attachment sAttachment = new Attachment();
sAttachment.channel = sChannel;
sChannel.register(selector, SelectionKey.OP_READ, sAttachment);
sAttachment.onStart();
}
}else{ //INVALID KEY
}
}catch(Exception e){
key.cancel();
attachment.onClosed();
e.printStackTrace();
}finally{
selectedKeys.remove();
}
}
}
public Attachment createServerSocket(final SocketAddress address){
final Attachment attachment = new Attachment();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
ServerSocketChannel ssChannel = ServerSocketChannel.open();
attachment.channel = ssChannel;
ssChannel.configureBlocking(false);
ssChannel.socket().bind(address);
ssChannel.register(selector, SelectionKey.OP_ACCEPT, attachment);
attachment.onStart();
} catch (IOException e) {
attachment.onClosed();
e.printStackTrace();
}
}
};
runOnNioThread(runnable);
return attachment;
}
public Attachment createDatagramSocket(final SocketAddress address){
final Attachment attachment = new Attachment();
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
DatagramChannel dChannel = DatagramChannel.open();
attachment.channel = dChannel;
dChannel.configureBlocking(false);
dChannel.socket().bind(address);
dChannel.register(selector, SelectionKey.OP_READ, attachment);
attachment.onStart();
} catch (IOException e) {
attachment.onClosed();
e.printStackTrace();
}
}
};
runOnNioThread(runnable);
return attachment;
}
public void sendToAll(ByteBuffer buffer){
for(Attachment a:attachments){
try {
if(a.channel instanceof SocketChannel){
a.send(buffer);
buffer.flip();
}else if(a.channel instanceof DatagramChannel){
a.sendToAll(buffer);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
NioExample nio = new NioExample();
nio.start();
nio.createServerSocket(new InetSocketAddress(5050));
nio.createServerSocket(new InetSocketAddress(5051));
nio.createDatagramSocket(new InetSocketAddress(5050));
nio.createDatagramSocket(new InetSocketAddress(5051));
}
public class Attachment{
SelectableChannel channel;
Map<SocketAddress, Long> remoteAddresses = new HashMap<SocketAddress, Long>();
void onStart(){
attachments.add(this);
System.out.println("Started Listening " + channel);
}
void onReceiveData(ByteBuffer buffer){
System.out.printf("Received TCP(%s): %s\n",
((SocketChannel)channel).socket().getRemoteSocketAddress(),
new String(buffer.array(), buffer.position(), buffer.limit()));
NioExample.this.sendToAll(buffer);
}
void onReceiveData(ByteBuffer buffer, SocketAddress remote){
remoteAddresses.put(remote, System.currentTimeMillis());
System.out.printf("Received UDP(%s): %s\n",
remote, new String(buffer.array(), buffer.position(), buffer.limit()));
NioExample.this.sendToAll(buffer);
}
void onClosed(){
attachments.remove(this);
System.out.println("Closed " + channel);
}
public synchronized void send(ByteBuffer data) throws IOException{
SocketChannel sChannel = (SocketChannel)channel;
sChannel.write(data);
}
public synchronized void sendTo(ByteBuffer data, SocketAddress remote) throws IOException{
if((System.currentTimeMillis() - remoteAddresses.get(remote)) > (TimeUnit.MINUTES.toMillis(5))){
remoteAddresses.remove(remote);
System.out.println("Deleted Entry " + remote);
return;
}
DatagramChannel dChannel = (DatagramChannel)channel;
dChannel.send(data, remote);
}
public void sendToAll(ByteBuffer data) throws IOException{
Iterator<SocketAddress> addresses = remoteAddresses.keySet().iterator();
while(addresses.hasNext()){
sendTo(data, addresses.next());
data.flip();
}
}
}
}