static
This commit is contained in:
@@ -209,17 +209,13 @@ public class ArcNetProvider implements NetProvider{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//TODO remove
|
|
||||||
static AsyncUdp udp = new AsyncUdp();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> invalid){
|
public void pingHost(String address, int port, Cons<Host> valid, Cons<Exception> invalid){
|
||||||
long time = Time.millis();
|
long time = Time.millis();
|
||||||
var socket = new InetSocketAddress(address, port);
|
var socket = new InetSocketAddress(address, port);
|
||||||
Log.info("Time to resolve @: @", address, Time.timeSinceMillis(time));
|
Log.info("Time to resolve @: @", address, Time.timeSinceMillis(time));
|
||||||
|
|
||||||
udp.send(socket, 2000, 512, ByteBuffer.wrap(new byte[]{-2, 1}), data -> {
|
AsyncUdp.send(socket, 2000, 512, ByteBuffer.wrap(new byte[]{-2, 1}), data -> {
|
||||||
Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), socket.getAddress().getHostAddress(), data);
|
Host host = NetworkIO.readServerData((int)Time.timeSinceMillis(time), socket.getAddress().getHostAddress(), data);
|
||||||
host.port = port;
|
host.port = port;
|
||||||
Core.app.post(() -> valid.get(host));
|
Core.app.post(() -> valid.get(host));
|
||||||
|
|||||||
@@ -10,26 +10,72 @@ import java.nio.channels.*;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
public class AsyncUdp implements Runnable{
|
public class AsyncUdp{
|
||||||
Selector selector;
|
static Selector selector;
|
||||||
DelayQueue<Request> removals = new DelayQueue<>();
|
static DelayQueue<Request> removals = new DelayQueue<>();
|
||||||
TaskQueue tasks = new TaskQueue();
|
static TaskQueue tasks = new TaskQueue();
|
||||||
int emptySelects;
|
static int emptySelects;
|
||||||
|
|
||||||
public AsyncUdp(){
|
static{
|
||||||
try{
|
try{
|
||||||
selector = Selector.open();
|
selector = Selector.open();
|
||||||
|
|
||||||
Threads.daemon("AsyncUDP", this);
|
//handle requests and tasks
|
||||||
|
Threads.daemon("AsyncUDP", () -> {
|
||||||
|
while(true){
|
||||||
|
try{
|
||||||
|
long startTime = Time.millis();
|
||||||
|
int selected = selector.select(0);
|
||||||
|
|
||||||
|
tasks.run();
|
||||||
|
|
||||||
|
if(selected == 0){
|
||||||
|
//prevent hogging the CPU due to empty selects as per Kryonet implementation
|
||||||
|
if(emptySelects++ >= 100){
|
||||||
|
emptySelects = 0;
|
||||||
|
long elapsedTime = System.currentTimeMillis() - startTime;
|
||||||
|
if(elapsedTime < 25) Threads.sleep(25 - elapsedTime);
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys = selector.selectedKeys();
|
||||||
|
for(Iterator<SelectionKey> iter = keys.iterator(); iter.hasNext(); ){
|
||||||
|
var key = iter.next();
|
||||||
|
iter.remove();
|
||||||
|
|
||||||
|
if(key.isReadable() && key.isValid()){
|
||||||
|
var request = (Request)key.attachment();
|
||||||
|
try{
|
||||||
|
var channel = (DatagramChannel)key.channel();
|
||||||
|
var buffer = ByteBuffer.allocate(request.bufferSize);
|
||||||
|
channel.receive(buffer);
|
||||||
|
buffer.flip();
|
||||||
|
|
||||||
|
request.received.get(buffer);
|
||||||
|
request.close();
|
||||||
|
}catch(IOException error){
|
||||||
|
request.fail(error);
|
||||||
|
//TODO remove logging, this is not needed outside of debugging
|
||||||
|
Log.err(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}catch(IOException e){
|
||||||
|
Log.err(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
//remove requests with the delay queue
|
||||||
Threads.daemon("AsyncUDP-Delay", () -> {
|
Threads.daemon("AsyncUDP-Delay", () -> {
|
||||||
while(true){
|
while(true){
|
||||||
try{
|
try{
|
||||||
var request = removals.take();
|
var request = removals.take();
|
||||||
synchronized(request){
|
tasks.post(() -> request.fail(new TimeoutException()));
|
||||||
request.cancel(new TimeoutException());
|
selector.wakeup();
|
||||||
}
|
}catch(InterruptedException ignored){}
|
||||||
}catch(InterruptedException ignored){
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}catch(IOException e){
|
}catch(IOException e){
|
||||||
@@ -37,8 +83,7 @@ public class AsyncUdp implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(InetSocketAddress address, int timeout, int bufferSize, ByteBuffer data, Cons<ByteBuffer> received, Cons<Exception> failed){
|
public static void send(InetSocketAddress address, int timeout, int bufferSize, ByteBuffer data, Cons<ByteBuffer> received, Cons<Exception> failed){
|
||||||
//TODO is it worth posting to the task queue when you can just run it here? shouldn't be very expensive
|
|
||||||
tasks.post(() -> {
|
tasks.post(() -> {
|
||||||
try{
|
try{
|
||||||
DatagramChannel channel = selector.provider().openDatagramChannel();
|
DatagramChannel channel = selector.provider().openDatagramChannel();
|
||||||
@@ -60,56 +105,6 @@ public class AsyncUdp implements Runnable{
|
|||||||
selector.wakeup();
|
selector.wakeup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run(){
|
|
||||||
while(true){
|
|
||||||
try{
|
|
||||||
long startTime = Time.millis();
|
|
||||||
int selected = selector.select(0);
|
|
||||||
|
|
||||||
tasks.run();
|
|
||||||
|
|
||||||
if(selected == 0){
|
|
||||||
//prevent hogging the CPU due to empty selects as per Kryonet implementation
|
|
||||||
if(emptySelects++ >= 100){
|
|
||||||
emptySelects = 0;
|
|
||||||
long elapsedTime = System.currentTimeMillis() - startTime;
|
|
||||||
if(elapsedTime < 25) Threads.sleep(25 - elapsedTime);
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var keys = selector.selectedKeys();
|
|
||||||
for(Iterator<SelectionKey> iter = keys.iterator(); iter.hasNext(); ){
|
|
||||||
var key = iter.next();
|
|
||||||
iter.remove();
|
|
||||||
|
|
||||||
if(key.isReadable()){
|
|
||||||
var request = (Request)key.attachment();
|
|
||||||
|
|
||||||
synchronized(request){
|
|
||||||
try{
|
|
||||||
var channel = (DatagramChannel)key.channel();
|
|
||||||
var buffer = ByteBuffer.allocate(request.bufferSize);
|
|
||||||
channel.receive(buffer);
|
|
||||||
buffer.flip();
|
|
||||||
|
|
||||||
request.received.get(buffer);
|
|
||||||
request.close();
|
|
||||||
}catch(IOException error){
|
|
||||||
request.cancel(error);
|
|
||||||
Log.err(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}catch(IOException e){
|
|
||||||
Log.err(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static class Request implements Delayed{
|
static class Request implements Delayed{
|
||||||
final InetSocketAddress address;
|
final InetSocketAddress address;
|
||||||
final long timeout, connectStartMs;
|
final long timeout, connectStartMs;
|
||||||
@@ -142,7 +137,7 @@ public class AsyncUdp implements Runnable{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancel(Exception error){
|
void fail(Exception error){
|
||||||
if(!key.isValid()) return;
|
if(!key.isValid()) return;
|
||||||
failed.get(error);
|
failed.get(error);
|
||||||
close();
|
close();
|
||||||
|
|||||||
Reference in New Issue
Block a user