Last active
December 21, 2020 08:37
-
-
Save kimathie/b6ed6376fca9b13c1943127a929b7239 to your computer and use it in GitHub Desktop.
A NIO UDP server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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.SelectionKey; | |
import java.nio.channels.Selector; | |
import java.util.concurrent.ExecutorService; | |
import java.util.concurrent.Executors; | |
import java.util.Iterator; | |
import java.util.Set; | |
/** | |
* | |
* @author kimathie | |
*/ | |
public class UdpServer { | |
private final Acceptor acceptor; | |
public UdpServer(String host, int port) { | |
this.acceptor = new Acceptor(host, port); | |
} | |
public void start() { | |
this.acceptor.start(); | |
} | |
public void stop() { | |
this.acceptor.interrupt(); | |
} | |
class Acceptor extends Thread { | |
private final int port; | |
private final String host; | |
private Selector selector; | |
private final ExecutorService pool; | |
public Acceptor(String host, int port) { | |
this.host = host; | |
this.port = port; | |
this.pool = Executors.newFixedThreadPool(3); | |
} | |
@Override | |
public void run() { | |
try { | |
this.selector = Selector.open(); | |
DatagramChannel server = DatagramChannel.open(); | |
server.bind(new InetSocketAddress(host, port)); | |
server.configureBlocking(false); | |
server.register(selector, SelectionKey.OP_READ); | |
SocketAddress localAddress = server.getLocalAddress(); | |
System.out.println("Server " + localAddress + " open."); | |
while (true) { | |
if (isInterrupted()) { | |
interrupt(); | |
pool.shutdownNow(); | |
System.out.println("Server " + localAddress + " closed."); | |
break; | |
} | |
int ready = selector.select(); | |
if (ready != 0) { | |
Set<SelectionKey> selectedKeys = selector.selectedKeys(); | |
Iterator<SelectionKey> selectionKeys = selectedKeys.iterator(); | |
while (selectionKeys.hasNext()) { | |
SelectionKey key = selectionKeys.next(); | |
if (!key.isValid()) { | |
continue; | |
} | |
processKey(key); | |
selectionKeys.remove(); | |
} | |
} | |
} | |
} catch (IOException e) { | |
interrupt(); | |
} | |
} | |
private void processKey(SelectionKey key) { | |
switch (key.interestOps()) { | |
case SelectionKey.OP_READ: { | |
try { | |
DatagramChannel channel = (DatagramChannel) key.channel(); | |
ByteBuffer buffer = ByteBuffer.allocate(1024 * 8); | |
SocketAddress remoteAddress = channel.receive(buffer); | |
pool.execute(() -> { | |
int len = buffer.position(); | |
byte[] bytes = new byte[len]; | |
for (int i = 0; i < len; i++) { | |
bytes[i] = buffer.get(i); | |
} | |
System.out.println("data of length " + bytes.length + " read"); | |
buffer.flip(); | |
buffer.clear(); | |
channel.send(buffer.wrap(bytes), remoteAddress); | |
System.out.println("data of length " + bytes.length + " written"); | |
}); | |
} catch (IOException e) { | |
key.cancel(); | |
e.printStackTrace(); | |
} | |
} | |
break; | |
} | |
} | |
} | |
public static void main(String[] args) { | |
UdpServer server = new UdpServer("127.0.0.1", 8191); | |
server.start(); | |
Runtime.getRuntime().addShutdownHook(new Thread(() -> { | |
server.stop(); | |
}, "main")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment